Skip to content

Commit b0f362c

Browse files
author
Olexandr Pavlyuk
committed
bpo-43633 Improve the textual representation of IPv4-mapped IPv6 addresses
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).
1 parent 3407d76 commit b0f362c

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

Lib/ipaddress.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1918,8 +1918,40 @@ def __init__(self, address):
19181918

19191919
self._ip = self._ip_int_from_string(addr_str)
19201920

1921+
def _explode_shorthand_ip_string(self):
1922+
ipv4_mapped = self.ipv4_mapped
1923+
if ipv4_mapped is None:
1924+
long_form = super()._explode_shorthand_ip_string()
1925+
else:
1926+
prefix_len = 30
1927+
raw_exploded_str = super()._explode_shorthand_ip_string()
1928+
long_form = "%s%s" % (raw_exploded_str[:prefix_len], str(ipv4_mapped))
1929+
return long_form
1930+
1931+
def _ipv4_mapped_ipv6_to_str(self):
1932+
"""Return convenient text representation of IPv4-mapped IPv6 address
1933+
1934+
See RFC 4291 2.5.5.2, 2.2 p.3 for details.
1935+
1936+
Returns:
1937+
A string, 'x:x:x:x:x:x:d.d.d.d', where the 'x's are the hexadecimal values of
1938+
the six high-order 16-bit pieces of the address, and the 'd's are
1939+
the decimal values of the four low-order 8-bit pieces of the
1940+
address (standard IPv4 representation) as defined in RFC 4291 2.2 p.3.
1941+
1942+
"""
1943+
ipv4_mapped = self.ipv4_mapped
1944+
if ipv4_mapped is None:
1945+
raise AddressValueError("Can not apply to non-IPv4-mapped IPv6 address %s" % str(self))
1946+
high_order_bits = self._ip >> 32
1947+
return "%s:%s" % (self._string_from_ip_int(high_order_bits), str(ipv4_mapped))
1948+
19211949
def __str__(self):
1922-
ip_str = super().__str__()
1950+
ipv4_mapped = self.ipv4_mapped
1951+
if ipv4_mapped is None:
1952+
ip_str = super().__str__()
1953+
else:
1954+
ip_str = self._ipv4_mapped_ipv6_to_str()
19231955
return ip_str + '%' + self._scope_id if self._scope_id else ip_str
19241956

19251957
def __hash__(self):

Lib/test/test_ipaddress.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,13 @@ def testGetIp(self):
12971297
self.assertEqual(str(self.ipv6_scoped_interface.ip),
12981298
'2001:658:22a:cafe:200::1')
12991299

1300+
def testIPv6IPv4MappedStringRepresentation(self):
1301+
ipv6_ipv4_mapped_str = '::ffff:1.2.3.4'
1302+
ipv6_ipv4_mapped_address = ipaddress.IPv6Address(ipv6_ipv4_mapped_str)
1303+
ipv6_ipv4_mapped_interface = ipaddress.IPv6Interface(ipv6_ipv4_mapped_str)
1304+
self.assertEqual(str(ipv6_ipv4_mapped_address), ipv6_ipv4_mapped_str)
1305+
self.assertEqual(str(ipv6_ipv4_mapped_interface.ip), ipv6_ipv4_mapped_str)
1306+
13001307
def testGetScopeId(self):
13011308
self.assertEqual(self.ipv6_address.scope_id,
13021309
None)
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
Improve the textual representation of IPv4-mapped IPv6 addresses to :mod:`ipaddress`. Patch by Oleksandr
2-
Pavliuk.
1+
Improve the textual representation of IPv4-mapped IPv6 addresses (:rfc:`4291` Sections 2.2, 2.5.5.2) in :mod:`ipaddress.IPv6Address`. Patch by Oleksandr Pavliuk.

0 commit comments

Comments
 (0)