From 2780674a161d8db8a7d1e362e4a34591f93525f1 Mon Sep 17 00:00:00 2001 From: wouter bolsterlee Date: Mon, 9 May 2022 23:36:30 +0200 Subject: [PATCH] gh-92573: Add IPv4Address.ipv6_mapped attribute This adds a IPv4Address.ipv6_mapped attribute to mirror IPv6Address.ipv4_mapped. Closes #92573. --- Doc/library/ipaddress.rst | 10 +++++++++- Lib/ipaddress.py | 9 +++++++++ Lib/test/test_ipaddress.py | 8 ++++++++ .../2022-05-09-23-41-56.gh-issue-92573.e5VQuu.rst | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2022-05-09-23-41-56.gh-issue-92573.e5VQuu.rst diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index 9c2dff55703273..d4752f8c841e52 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -222,6 +222,13 @@ write code that handles both IP versions correctly. Address objects are .. _iana-ipv4-special-registry: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml .. _iana-ipv6-special-registry: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml + .. attribute:: ipv6_mapped + + This property gives the IPv4-mapped IPv6 address corresponding to this IPv4 + address. The resulting :class:`IPv6Address` is in the range + ``::ffff:0:0/96`` as defined by :RFC:`4291`. See also + :attr:`~IPv6Address.ipv4_mapped`. + .. method:: IPv4Address.__format__(fmt) Returns a string representation of the IP address, controlled by @@ -321,7 +328,8 @@ write code that handles both IP versions correctly. Address objects are For addresses that appear to be IPv4 mapped addresses (starting with ``::FFFF/96``), this property will report the embedded IPv4 address. - For any other address, this property will be ``None``. + For any other address, this property will be ``None``. See also + :attr:`~IPv4Address.ipv6_mapped`. .. attribute:: scope_id diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 3f15601e700d68..89f7014bf1a684 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1379,6 +1379,15 @@ def is_link_local(self): """ return self in self._constants._linklocal_network + @property + def ipv6_mapped(self): + """Return the IPv4-mapped IPv6 address corresponding to this IPv4 address. + + Returns: + The corresponding IPv4-mapped IPv6 address. + """ + return IPv6Address(0xffff_0000_0000 | self._ip) + class IPv4Interface(IPv4Address): diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index c9ae7dab387ced..90ffb4e6c8be4e 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -2368,6 +2368,14 @@ def testIpv4MappedPrivateCheck(self): self.assertEqual( False, ipaddress.ip_address('::ffff:172.32.0.0').is_private) + def testIpv6Mapped(self): + self.assertEqual( + ipaddress.ip_address('1.2.3.4').ipv6_mapped, + ipaddress.ip_address('::ffff:102:304')) + self.assertEqual( + ipaddress.ip_address('1.2.3.4').ipv6_mapped, + ipaddress.ip_address('::ffff:1.2.3.4')) + def testAddrExclude(self): addr1 = ipaddress.ip_network('10.1.1.0/24') addr2 = ipaddress.ip_network('10.1.1.0/26') diff --git a/Misc/NEWS.d/next/Library/2022-05-09-23-41-56.gh-issue-92573.e5VQuu.rst b/Misc/NEWS.d/next/Library/2022-05-09-23-41-56.gh-issue-92573.e5VQuu.rst new file mode 100644 index 00000000000000..5aaa201ad1849b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-09-23-41-56.gh-issue-92573.e5VQuu.rst @@ -0,0 +1,2 @@ +Add :attr:`ipaddress.IPv4Address.ipv6_mapped` to mirror +:attr:`ipaddress.IPv6Address.ipv4_mapped`.