[Python-checkins] gh-87799: Improve the textual representation of IPv4-mapped IPv6 addresses (#29345)
asvetlov
webhook-mailer at python.org
Mon Jul 31 10:33:31 EDT 2023
https://github.com/python/cpython/commit/f22bf8e3cf899896cf587099d29290cb43aa9724
commit: f22bf8e3cf899896cf587099d29290cb43aa9724
branch: main
author: opavliuk <40970635+opavlyuk at users.noreply.github.com>
committer: asvetlov <andrew.svetlov at gmail.com>
date: 2023-07-31T14:33:26Z
summary:
gh-87799: Improve the textual representation of IPv4-mapped IPv6 addresses (#29345)
Represent IPv4-mapped IPv6 address as 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).
---------
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Andrew Svetlov <andrew.svetlov at gmail.com>
files:
A Misc/NEWS.d/next/Library/2021-10-31-16-06-28.bpo-43633.vflwXv.rst
M Lib/ipaddress.py
M Lib/test/test_ipaddress.py
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index af1d5c4800cce..f5aba434fd425 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1923,8 +1923,40 @@ def __init__(self, address):
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):
- 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
def __hash__(self):
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index a5388b2e5debd..6f204948c9fc4 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -1321,6 +1321,17 @@ def testGetIp(self):
self.assertEqual(str(self.ipv6_scoped_interface.ip),
'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):
self.assertEqual(self.ipv6_address.scope_id,
None)
diff --git a/Misc/NEWS.d/next/Library/2021-10-31-16-06-28.bpo-43633.vflwXv.rst b/Misc/NEWS.d/next/Library/2021-10-31-16-06-28.bpo-43633.vflwXv.rst
new file mode 100644
index 0000000000000..025de1e1a7d6e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-10-31-16-06-28.bpo-43633.vflwXv.rst
@@ -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.
More information about the Python-checkins
mailing list