mirror of
https://github.com/python/cpython.git
synced 2025-09-29 11:45:57 +00:00
gh-87799: Improve the textual representation of IPv4-mapped IPv6 addresses (#29345)
Represent IPv4-mapped IPv6 address as x❌x❌x❌d.d.d.d, where the 'x's are the hexadecimal values of the six high-order 16-bit pieces of the address, and the 'd's are the decimal values of the four low-order 8-bit pieces of the address (standard IPv4 representation). --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
This commit is contained in:
parent
520efecfc3
commit
f22bf8e3cf
3 changed files with 45 additions and 1 deletions
|
@ -1923,8 +1923,40 @@ class IPv6Address(_BaseV6, _BaseAddress):
|
||||||
|
|
||||||
self._ip = self._ip_int_from_string(addr_str)
|
self._ip = self._ip_int_from_string(addr_str)
|
||||||
|
|
||||||
|
def _explode_shorthand_ip_string(self):
|
||||||
|
ipv4_mapped = self.ipv4_mapped
|
||||||
|
if ipv4_mapped is None:
|
||||||
|
long_form = super()._explode_shorthand_ip_string()
|
||||||
|
else:
|
||||||
|
prefix_len = 30
|
||||||
|
raw_exploded_str = super()._explode_shorthand_ip_string()
|
||||||
|
long_form = "%s%s" % (raw_exploded_str[:prefix_len], str(ipv4_mapped))
|
||||||
|
return long_form
|
||||||
|
|
||||||
|
def _ipv4_mapped_ipv6_to_str(self):
|
||||||
|
"""Return convenient text representation of IPv4-mapped IPv6 address
|
||||||
|
|
||||||
|
See RFC 4291 2.5.5.2, 2.2 p.3 for details.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A string, 'x:x:x:x:x:x:d.d.d.d', where the 'x's are the hexadecimal values of
|
||||||
|
the six high-order 16-bit pieces of the address, and the 'd's are
|
||||||
|
the decimal values of the four low-order 8-bit pieces of the
|
||||||
|
address (standard IPv4 representation) as defined in RFC 4291 2.2 p.3.
|
||||||
|
|
||||||
|
"""
|
||||||
|
ipv4_mapped = self.ipv4_mapped
|
||||||
|
if ipv4_mapped is None:
|
||||||
|
raise AddressValueError("Can not apply to non-IPv4-mapped IPv6 address %s" % str(self))
|
||||||
|
high_order_bits = self._ip >> 32
|
||||||
|
return "%s:%s" % (self._string_from_ip_int(high_order_bits), str(ipv4_mapped))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
ip_str = super().__str__()
|
ipv4_mapped = self.ipv4_mapped
|
||||||
|
if ipv4_mapped is None:
|
||||||
|
ip_str = super().__str__()
|
||||||
|
else:
|
||||||
|
ip_str = self._ipv4_mapped_ipv6_to_str()
|
||||||
return ip_str + '%' + self._scope_id if self._scope_id else ip_str
|
return ip_str + '%' + self._scope_id if self._scope_id else ip_str
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
|
|
|
@ -1321,6 +1321,17 @@ class IpaddrUnitTest(unittest.TestCase):
|
||||||
self.assertEqual(str(self.ipv6_scoped_interface.ip),
|
self.assertEqual(str(self.ipv6_scoped_interface.ip),
|
||||||
'2001:658:22a:cafe:200::1')
|
'2001:658:22a:cafe:200::1')
|
||||||
|
|
||||||
|
def testIPv6IPv4MappedStringRepresentation(self):
|
||||||
|
long_prefix = '0000:0000:0000:0000:0000:ffff:'
|
||||||
|
short_prefix = '::ffff:'
|
||||||
|
ipv4 = '1.2.3.4'
|
||||||
|
ipv6_ipv4_str = short_prefix + ipv4
|
||||||
|
ipv6_ipv4_addr = ipaddress.IPv6Address(ipv6_ipv4_str)
|
||||||
|
ipv6_ipv4_iface = ipaddress.IPv6Interface(ipv6_ipv4_str)
|
||||||
|
self.assertEqual(str(ipv6_ipv4_addr), ipv6_ipv4_str)
|
||||||
|
self.assertEqual(ipv6_ipv4_addr.exploded, long_prefix + ipv4)
|
||||||
|
self.assertEqual(str(ipv6_ipv4_iface.ip), ipv6_ipv4_str)
|
||||||
|
|
||||||
def testGetScopeId(self):
|
def testGetScopeId(self):
|
||||||
self.assertEqual(self.ipv6_address.scope_id,
|
self.assertEqual(self.ipv6_address.scope_id,
|
||||||
None)
|
None)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improve the textual representation of IPv4-mapped IPv6 addresses (:rfc:`4291` Sections 2.2, 2.5.5.2) in :mod:`ipaddress`. Patch by Oleksandr Pavliuk.
|
Loading…
Add table
Add a link
Reference in a new issue