mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-34788: Add support for scoped IPv6 addresses (GH-13772)
Automerge-Triggered-By: @asvetlov
This commit is contained in:
parent
be7ead62db
commit
21da76d1f1
7 changed files with 544 additions and 37 deletions
|
@ -1836,6 +1836,26 @@ class _BaseV6:
|
|||
reverse_chars = self.exploded[::-1].replace(':', '')
|
||||
return '.'.join(reverse_chars) + '.ip6.arpa'
|
||||
|
||||
@staticmethod
|
||||
def _split_scope_id(ip_str):
|
||||
"""Helper function to parse IPv6 string address with scope id.
|
||||
|
||||
See RFC 4007 for details.
|
||||
|
||||
Args:
|
||||
ip_str: A string, the IPv6 address.
|
||||
|
||||
Returns:
|
||||
(addr, scope_id) tuple.
|
||||
|
||||
"""
|
||||
addr, sep, scope_id = ip_str.partition('%')
|
||||
if not sep:
|
||||
scope_id = None
|
||||
elif not scope_id or '%' in scope_id:
|
||||
raise AddressValueError('Invalid IPv6 address: "%r"' % ip_str)
|
||||
return addr, scope_id
|
||||
|
||||
@property
|
||||
def max_prefixlen(self):
|
||||
return self._max_prefixlen
|
||||
|
@ -1849,7 +1869,7 @@ class IPv6Address(_BaseV6, _BaseAddress):
|
|||
|
||||
"""Represent and manipulate single IPv6 Addresses."""
|
||||
|
||||
__slots__ = ('_ip', '__weakref__')
|
||||
__slots__ = ('_ip', '_scope_id', '__weakref__')
|
||||
|
||||
def __init__(self, address):
|
||||
"""Instantiate a new IPv6 address object.
|
||||
|
@ -1872,12 +1892,14 @@ class IPv6Address(_BaseV6, _BaseAddress):
|
|||
if isinstance(address, int):
|
||||
self._check_int_address(address)
|
||||
self._ip = address
|
||||
self._scope_id = None
|
||||
return
|
||||
|
||||
# Constructing from a packed address
|
||||
if isinstance(address, bytes):
|
||||
self._check_packed_address(address, 16)
|
||||
self._ip = int.from_bytes(address, 'big')
|
||||
self._scope_id = None
|
||||
return
|
||||
|
||||
# Assume input argument to be string or any object representation
|
||||
|
@ -1885,8 +1907,37 @@ class IPv6Address(_BaseV6, _BaseAddress):
|
|||
addr_str = str(address)
|
||||
if '/' in addr_str:
|
||||
raise AddressValueError("Unexpected '/' in %r" % address)
|
||||
addr_str, self._scope_id = self._split_scope_id(addr_str)
|
||||
|
||||
self._ip = self._ip_int_from_string(addr_str)
|
||||
|
||||
def __str__(self):
|
||||
ip_str = super().__str__()
|
||||
return ip_str + '%' + self._scope_id if self._scope_id else ip_str
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self._ip, self._scope_id))
|
||||
|
||||
def __eq__(self, other):
|
||||
address_equal = super().__eq__(other)
|
||||
if address_equal is NotImplemented:
|
||||
return NotImplemented
|
||||
if not address_equal:
|
||||
return False
|
||||
return self._scope_id == getattr(other, '_scope_id', None)
|
||||
|
||||
@property
|
||||
def scope_id(self):
|
||||
"""Identifier of a particular zone of the address's scope.
|
||||
|
||||
See RFC 4007 for details.
|
||||
|
||||
Returns:
|
||||
A string identifying the zone of the address if specified, else None.
|
||||
|
||||
"""
|
||||
return self._scope_id
|
||||
|
||||
@property
|
||||
def packed(self):
|
||||
"""The binary representation of this address."""
|
||||
|
@ -2040,7 +2091,7 @@ class IPv6Interface(IPv6Address):
|
|||
return self.network.hostmask
|
||||
|
||||
def __str__(self):
|
||||
return '%s/%d' % (self._string_from_ip_int(self._ip),
|
||||
return '%s/%d' % (super().__str__(),
|
||||
self._prefixlen)
|
||||
|
||||
def __eq__(self, other):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue