diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 9c7a0a46f4f0e1..d791c5aaf9d5b5 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1026,15 +1026,14 @@ def is_multicast(self): @staticmethod def _is_subnet_of(a, b): - try: - # Always false if one is v4 and the other is v6. - if a.version != b.version: - raise TypeError(f"{a} and {b} are not of the same version") - return (b.network_address <= a.network_address and - b.broadcast_address >= a.broadcast_address) - except AttributeError: - raise TypeError(f"Unable to test subnet containment " - f"between {a} and {b}") + if not (isinstance(a, _BaseNetwork) and isinstance(b, _BaseNetwork)): + raise TypeError(f"Unable to test subnet containment between " + f"{a} and {b}: both must be network objects") + # Always false if one is v4 and the other is v6. + if a.version != b.version: + raise TypeError(f"{a} and {b} are not of the same version") + return (b.network_address <= a.network_address and + b.broadcast_address >= a.broadcast_address) def subnet_of(self, other): """Return True if this network is a subnet of other.""" diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index a74b692784eb59..73e954a2276d67 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -723,6 +723,20 @@ def test_subnet_of_mixed_types(self): ipaddress.IPv6Network('::1/128').subnet_of( ipaddress.IPv4Network('10.0.0.0/30')) + def test_subnet_of_non_network(self): + # Passing something that is not a network object (e.g. an address) + # must raise a clear TypeError rather than masking an internal + # AttributeError (gh-153769). + net = ipaddress.IPv4Network('10.0.0.0/30') + for other in (ipaddress.IPv4Address('10.0.0.1'), '10.0.0.0/30', 42): + for method in (net.subnet_of, net.supernet_of): + with self.assertRaises(TypeError) as cm: + method(other) + self.assertIn('network', str(cm.exception)) + # The error should not be a swallowed AttributeError. + self.assertNotIsInstance(cm.exception.__context__, + AttributeError) + class NetmaskTestMixin_v6(CommonTestMixin_v6): """Input validation on interfaces and networks is very similar""" diff --git a/Misc/ACKS b/Misc/ACKS index fec00c1b272f4e..5fe1d8cd1121ee 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -2008,6 +2008,7 @@ Wm. Keith van der Meulen Eric N. Vander Weele Andrew Vant Atul Varma +Vyron Vasileiadis Dmitry Vasiliev Sebastian Ortiz Vasquez Alexandre Vassalotti diff --git a/Misc/NEWS.d/next/Library/2026-07-19-16-30-00.gh-issue-153769.STygbq.rst b/Misc/NEWS.d/next/Library/2026-07-19-16-30-00.gh-issue-153769.STygbq.rst new file mode 100644 index 00000000000000..587ae0c912b98d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-19-16-30-00.gh-issue-153769.STygbq.rst @@ -0,0 +1,5 @@ +:meth:`~ipaddress.IPv4Network.subnet_of` and +:meth:`~ipaddress.IPv4Network.supernet_of` now raise a clear +:exc:`TypeError` when passed an argument that is not a network object, +such as an address, instead of a confusing error that masked an internal +:exc:`AttributeError`.