bpo-34788: Add support for scoped IPv6 addresses (GH-13772)



Automerge-Triggered-By: @asvetlov
diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst
index 140401d..5938439 100644
--- a/Doc/library/ipaddress.rst
+++ b/Doc/library/ipaddress.rst
@@ -217,11 +217,20 @@
       :RFC:`4291` for details.  For example,
       ``"0000:0000:0000:0000:0000:0abc:0007:0def"`` can be compressed to
       ``"::abc:7:def"``.
+
+      Optionally, the string may also have a scope zone ID, expressed
+      with a suffix ``%scope_id``. If present, the scope ID must be non-empty,
+      and may not contain ``%``.
+      See :RFC:`4007` for details.
+      For example, ``fe80::1234%1`` might identify address ``fe80::1234`` on the first link of the node.
    2. An integer that fits into 128 bits.
    3. An integer packed into a :class:`bytes` object of length 16, big-endian.
 
+
    >>> ipaddress.IPv6Address('2001:db8::1000')
    IPv6Address('2001:db8::1000')
+   >>> ipaddress.IPv6Address('ff02::5678%1')
+   IPv6Address('ff02::5678%1')
 
    .. attribute:: compressed
 
@@ -268,6 +277,12 @@
       ``::FFFF/96``), this property will report the embedded IPv4 address.
       For any other address, this property will be ``None``.
 
+   .. attribute:: scope_id
+
+      For scoped addresses as defined by :RFC:`4007`, this property identifies
+      the particular zone of the address's scope that the address belongs to,
+      as a string. When no scope zone is specified, this property will be ``None``.
+
    .. attribute:: sixtofour
 
       For addresses that appear to be 6to4 addresses  (starting with
@@ -299,6 +314,8 @@
    >>> int(ipaddress.IPv6Address('::1'))
    1
 
+Note that IPv6 scoped addresses are converted to integers without scope zone ID.
+
 
 Operators
 ^^^^^^^^^
@@ -311,8 +328,9 @@
 Comparison operators
 """"""""""""""""""""
 
-Address objects can be compared with the usual set of comparison operators.  Some
-examples::
+Address objects can be compared with the usual set of comparison operators.
+Same IPv6 addresses with different scope zone IDs are not equal.
+Some examples::
 
    >>> IPv4Address('127.0.0.2') > IPv4Address('127.0.0.1')
    True
@@ -320,6 +338,10 @@
    False
    >>> IPv4Address('127.0.0.2') != IPv4Address('127.0.0.1')
    True
+   >>> IPv6Address('fe80::1234') == IPv6Address('fe80::1234%1')
+   False
+   >>> IPv6Address('fe80::1234%1') != IPv6Address('fe80::1234%2')
+   True
 
 
 Arithmetic operators
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index 2cc946c..5426b5a 100755
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -78,15 +78,15 @@
     Python programs.
 
 - For :const:`AF_INET6` address family, a four-tuple ``(host, port, flowinfo,
-  scopeid)`` is used, where *flowinfo* and *scopeid* represent the ``sin6_flowinfo``
+  scope_id)`` is used, where *flowinfo* and *scope_id* represent the ``sin6_flowinfo``
   and ``sin6_scope_id`` members in :const:`struct sockaddr_in6` in C.  For
-  :mod:`socket` module methods, *flowinfo* and *scopeid* can be omitted just for
-  backward compatibility.  Note, however, omission of *scopeid* can cause problems
+  :mod:`socket` module methods, *flowinfo* and *scope_id* can be omitted just for
+  backward compatibility.  Note, however, omission of *scope_id* can cause problems
   in manipulating scoped IPv6 addresses.
 
   .. versionchanged:: 3.7
-     For multicast addresses (with *scopeid* meaningful) *address* may not contain
-     ``%scope`` (or ``zone id``) part. This information is superfluous and may
+     For multicast addresses (with *scope_id* meaningful) *address* may not contain
+     ``%scope_id`` (or ``zone id``) part. This information is superfluous and may
      be safely omitted (recommended).
 
 - :const:`AF_NETLINK` sockets are represented as pairs ``(pid, groups)``.
@@ -738,7 +738,7 @@
    :const:`AI_CANONNAME` is part of the *flags* argument; else *canonname*
    will be empty.  *sockaddr* is a tuple describing a socket address, whose
    format depends on the returned *family* (a ``(address, port)`` 2-tuple for
-   :const:`AF_INET`, a ``(address, port, flow info, scope id)`` 4-tuple for
+   :const:`AF_INET`, a ``(address, port, flowinfo, scope_id)`` 4-tuple for
    :const:`AF_INET6`), and is meant to be passed to the :meth:`socket.connect`
    method.
 
@@ -759,7 +759,7 @@
 
    .. versionchanged:: 3.7
       for IPv6 multicast addresses, string representing an address will not
-      contain ``%scope`` part.
+      contain ``%scope_id`` part.
 
 .. function:: getfqdn([name])
 
@@ -827,8 +827,8 @@
    or numeric address representation in *host*.  Similarly, *port* can contain a
    string port name or a numeric port number.
 
-   For IPv6 addresses, ``%scope`` is appended to the host part if *sockaddr*
-   contains meaningful *scopeid*. Usually this happens for multicast addresses.
+   For IPv6 addresses, ``%scope_id`` is appended to the host part if *sockaddr*
+   contains meaningful *scope_id*. Usually this happens for multicast addresses.
 
    For more information about *flags* you can consult :manpage:`getnameinfo(3)`.
 
@@ -1354,7 +1354,7 @@
 
    .. versionchanged:: 3.7
       For multicast IPv6 address, first item of *address* does not contain
-      ``%scope`` part anymore. In order to get full IPv6 address use
+      ``%scope_id`` part anymore. In order to get full IPv6 address use
       :func:`getnameinfo`.
 
 .. method:: socket.recvmsg(bufsize[, ancbufsize[, flags]])