Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 62482d9

Browse filesBrowse files
committed
fix: avoid loading adapter list twice
Load adapter list only once if operating in dual-stack mode. Also fix typing around adapater list to match what ifaddr defines.
1 parent 389a8a2 commit 62482d9
Copy full SHA for 62482d9

File tree

2 files changed

+44
-11
lines changed
Filter options

2 files changed

+44
-11
lines changed

‎src/zeroconf/_utils/net.py

Copy file name to clipboardExpand all lines: src/zeroconf/_utils/net.py
+18-9Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import socket
2929
import struct
3030
import sys
31-
from collections.abc import Sequence
31+
from collections.abc import Iterable, Sequence
3232
from typing import Any, Union, cast
3333

3434
import ifaddr
@@ -73,19 +73,27 @@ def _encode_address(address: str) -> bytes:
7373
return socket.inet_pton(address_family, address)
7474

7575

76-
def get_all_addresses() -> list[str]:
77-
return list({addr.ip for iface in ifaddr.get_adapters() for addr in iface.ips if addr.is_IPv4}) # type: ignore[misc]
76+
def get_all_addresses_ipv4(adapters: Iterable[ifaddr.Adapter]) -> list[str]:
77+
return list({addr.ip for iface in adapters for addr in iface.ips if addr.is_IPv4}) # type: ignore[misc]
7878

7979

80-
def get_all_addresses_v6() -> list[tuple[tuple[str, int, int], int]]:
80+
def get_all_addresses_ipv6(adapters: Iterable[ifaddr.Adapter]) -> list[tuple[tuple[str, int, int], int]]:
8181
# IPv6 multicast uses positive indexes for interfaces
8282
# TODO: What about multi-address interfaces?
8383
return list(
84-
{(addr.ip, iface.index) for iface in ifaddr.get_adapters() for addr in iface.ips if addr.is_IPv6} # type: ignore[misc]
84+
{(addr.ip, iface.index) for iface in adapters for addr in iface.ips if addr.is_IPv6} # type: ignore[misc]
8585
)
8686

8787

88-
def ip6_to_address_and_index(adapters: list[ifaddr.Adapter], ip: str) -> tuple[tuple[str, int, int], int]:
88+
def get_all_addresses() -> list[str]: # required for backwards compat
89+
return get_all_addresses_ipv4(ifaddr.get_adapters())
90+
91+
92+
def get_all_addresses_v6() -> list[tuple[tuple[str, int, int], int]]: # required for backwards compat
93+
return get_all_addresses_ipv6(ifaddr.get_adapters())
94+
95+
96+
def ip6_to_address_and_index(adapters: Iterable[ifaddr.Adapter], ip: str) -> tuple[tuple[str, int, int], int]:
8997
if "%" in ip:
9098
ip = ip[: ip.index("%")] # Strip scope_id.
9199
ipaddr = ipaddress.ip_address(ip)
@@ -102,7 +110,7 @@ def ip6_to_address_and_index(adapters: list[ifaddr.Adapter], ip: str) -> tuple[t
102110
raise RuntimeError(f"No adapter found for IP address {ip}")
103111

104112

105-
def interface_index_to_ip6_address(adapters: list[ifaddr.Adapter], index: int) -> tuple[str, int, int]:
113+
def interface_index_to_ip6_address(adapters: Iterable[ifaddr.Adapter], index: int) -> tuple[str, int, int]:
106114
for adapter in adapters:
107115
if adapter.index == index:
108116
for adapter_ip in adapter.ips:
@@ -152,10 +160,11 @@ def normalize_interface_choice(
152160
if ip_version != IPVersion.V6Only:
153161
result.append("0.0.0.0")
154162
elif choice is InterfaceChoice.All:
163+
adapters = ifaddr.get_adapters()
155164
if ip_version != IPVersion.V4Only:
156-
result.extend(get_all_addresses_v6())
165+
result.extend(get_all_addresses_ipv6(adapters))
157166
if ip_version != IPVersion.V6Only:
158-
result.extend(get_all_addresses())
167+
result.extend(get_all_addresses_ipv4(adapters))
159168
if not result:
160169
raise RuntimeError(
161170
f"No interfaces to listen on, check that any interfaces have IP version {ip_version}"

‎tests/utils/test_net.py

Copy file name to clipboardExpand all lines: tests/utils/test_net.py
+26-2Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,30 @@ def _generate_mock_adapters():
3535
return [mock_eth0, mock_lo0, mock_eth1, mock_vtun0]
3636

3737

38+
def test_get_all_addresses():
39+
"""Test public get_all_addresses API."""
40+
with patch(
41+
"zeroconf._utils.net.ifaddr.get_adapters",
42+
return_value=_generate_mock_adapters(),
43+
):
44+
from zeroconf import get_all_addresses
45+
addresses = get_all_addresses()
46+
assert isinstance(addresses, list)
47+
assert len(addresses) == 3
48+
49+
50+
def test_get_all_addresses_v6():
51+
"""Test public get_all_addresses_v6 API."""
52+
with patch(
53+
"zeroconf._utils.net.ifaddr.get_adapters",
54+
return_value=_generate_mock_adapters(),
55+
):
56+
from zeroconf import get_all_addresses_v6
57+
addresses = get_all_addresses_v6()
58+
assert isinstance(addresses, list)
59+
assert len(addresses) == 1
60+
61+
3862
def test_ip6_to_address_and_index():
3963
"""Test we can extract from mocked adapters."""
4064
adapters = _generate_mock_adapters()
@@ -84,8 +108,8 @@ def test_ip6_addresses_to_indexes():
84108
def test_normalize_interface_choice_errors():
85109
"""Test we generate exception on invalid input."""
86110
with (
87-
patch("zeroconf._utils.net.get_all_addresses", return_value=[]),
88-
patch("zeroconf._utils.net.get_all_addresses_v6", return_value=[]),
111+
patch("zeroconf._utils.net.get_all_addresses_ipv4", return_value=[]),
112+
patch("zeroconf._utils.net.get_all_addresses_ipv6", return_value=[]),
89113
pytest.raises(RuntimeError),
90114
):
91115
netutils.normalize_interface_choice(r.InterfaceChoice.All)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.