From 52ac85514a2247514530c7aa6c5ee691075b4012 Mon Sep 17 00:00:00 2001 From: acul71 Date: Sun, 6 Sep 2026 23:36:02 +0200 Subject: [PATCH] feat: add interface_multiaddrs() helper (fixes #122) Co-authored-by: Cursor --- README.rst | 7 ++++++- examples/thin_waist/thin_waist_example.py | 7 ++++++- multiaddr/__init__.py | 2 ++ multiaddr/utils.py | 14 ++++++++++++++ newsfragments/122.feature.rst | 1 + tests/test_interface_multiaddrs.py | 18 ++++++++++++++++++ tests/test_package_exports.py | 1 + 7 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 newsfragments/122.feature.rst create mode 100644 tests/test_interface_multiaddrs.py diff --git a/README.rst b/README.rst index 2f97a4b..9b104ee 100644 --- a/README.rst +++ b/README.rst @@ -235,7 +235,12 @@ Multiaddr provides thin waist address validation functionality to process multia .. code-block:: python from multiaddr import Multiaddr - from multiaddr.utils import get_thin_waist_addresses, get_network_addrs + from multiaddr.utils import get_thin_waist_addresses, get_network_addrs, interface_multiaddrs + + # List local interfaces as Multiaddr objects + for ma in interface_multiaddrs(): + print(ma) + # Multiaddr('/ip4/192.168.1.10'), ... # Network interface discovery ipv4_addrs = get_network_addrs(4) diff --git a/examples/thin_waist/thin_waist_example.py b/examples/thin_waist/thin_waist_example.py index 88123f3..ef6a607 100644 --- a/examples/thin_waist/thin_waist_example.py +++ b/examples/thin_waist/thin_waist_example.py @@ -12,7 +12,7 @@ import sys from multiaddr import Multiaddr -from multiaddr.utils import get_network_addrs, get_thin_waist_addresses +from multiaddr.utils import get_network_addrs, get_thin_waist_addresses, interface_multiaddrs def show_network_info(): @@ -28,6 +28,11 @@ def show_network_info(): print(f"Available IPv6 addresses: {ipv6_addrs}") print() + print("=== interface_multiaddrs() ===") + for ma in interface_multiaddrs(): + print(f" {ma}") + print() + def basic_examples(): """Show basic thin waist address validation examples.""" diff --git a/multiaddr/__init__.py b/multiaddr/__init__.py index 456004f..c2eed92 100755 --- a/multiaddr/__init__.py +++ b/multiaddr/__init__.py @@ -36,6 +36,7 @@ get_multiaddr_options, get_network_addrs, get_thin_waist_addresses, + interface_multiaddrs, is_ip6_link_local, is_ip_loopback, is_ip_unspecified, @@ -83,6 +84,7 @@ "get_multiaddr_options", "get_network_addrs", "get_thin_waist_addresses", + "interface_multiaddrs", "is_ip6_link_local", "is_ip_loopback", "is_ip_unspecified", diff --git a/multiaddr/utils.py b/multiaddr/utils.py index 8ff19dc..dc865ac 100644 --- a/multiaddr/utils.py +++ b/multiaddr/utils.py @@ -219,3 +219,17 @@ def get_thin_waist_addresses( # Return the specific address addr_str = f"/{ip_proto}/{options['host']}/{options['transport']}/{target_port}" return [Multiaddr(addr_str)] + + +def interface_multiaddrs() -> list[Multiaddr]: + """Return local interface addresses as Multiaddr objects. + + Uses :func:`get_network_addrs` for IPv4 and IPv6. Loopback and link-local + addresses are excluded (same filtering as ``get_network_addrs``). + """ + result: list[Multiaddr] = [] + for host in get_network_addrs(4): + result.append(Multiaddr(f"/ip4/{host}")) + for host in get_network_addrs(6): + result.append(Multiaddr(f"/ip6/{host}")) + return result diff --git a/newsfragments/122.feature.rst b/newsfragments/122.feature.rst new file mode 100644 index 0000000..3ab86bc --- /dev/null +++ b/newsfragments/122.feature.rst @@ -0,0 +1 @@ +Add ``interface_multiaddrs()`` to return local interface addresses as Multiaddr objects. diff --git a/tests/test_interface_multiaddrs.py b/tests/test_interface_multiaddrs.py new file mode 100644 index 0000000..5e5ac79 --- /dev/null +++ b/tests/test_interface_multiaddrs.py @@ -0,0 +1,18 @@ +from unittest.mock import patch + +from multiaddr import Multiaddr, interface_multiaddrs + + +def test_interface_multiaddrs_builds_multiaddrs(): + with patch("multiaddr.utils.get_network_addrs") as mock_addrs: + mock_addrs.side_effect = lambda family: (["192.0.2.10"] if family == 4 else ["2001:db8::1"]) + addrs = interface_multiaddrs() + assert addrs == [ + Multiaddr("/ip4/192.0.2.10"), + Multiaddr("/ip6/2001:db8::1"), + ] + + +def test_interface_multiaddrs_empty_when_no_interfaces(): + with patch("multiaddr.utils.get_network_addrs", return_value=[]): + assert interface_multiaddrs() == [] diff --git a/tests/test_package_exports.py b/tests/test_package_exports.py index 04a1928..8189c81 100644 --- a/tests/test_package_exports.py +++ b/tests/test_package_exports.py @@ -32,6 +32,7 @@ "get_multiaddr_options", "get_network_addrs", "get_thin_waist_addresses", + "interface_multiaddrs", "is_ip6_link_local", "is_ip_loopback", "is_ip_unspecified",