fix: make parsed_scoped_addresses return addresses in the same order … · python-zeroconf/python-zeroconf@9b6adcf
@@ -22,9 +22,8 @@
22222323import ipaddress
2424import random
25-import socket
2625from functools import lru_cache
27-from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union, cast
26+from typing import TYPE_CHECKING, Dict, List, Optional, Set, Union, cast
28272928from .._dns import (
3029DNSAddress,
@@ -40,7 +39,7 @@
4039from .._updates import RecordUpdate, RecordUpdateListener
4140from .._utils.asyncio import get_running_loop, run_coro_with_timeout
4241from .._utils.name import service_type_name
43-from .._utils.net import IPVersion, _encode_address, _is_v6_address
42+from .._utils.net import IPVersion, _encode_address
4443from .._utils.time import current_time_millis
4544from ..const import (
4645_CLASS_IN,
@@ -223,7 +222,14 @@ def properties(self) -> Dict:
223222return self._properties
224223225224def addresses_by_version(self, version: IPVersion) -> List[bytes]:
226-"""List addresses matching IP version."""
225+"""List addresses matching IP version.
226+227+ Addresses are guaranteed to be returned in LIFO (last in, first out)
228+ order with IPv4 addresses first and IPv6 addresses second.
229+230+ This means the first address will always be the most recently added
231+ address of the given IP version.
232+ """
227233if version == IPVersion.V4Only:
228234return [addr.packed for addr in self._ipv4_addresses]
229235if version == IPVersion.V6Only:
@@ -236,35 +242,47 @@ def addresses_by_version(self, version: IPVersion) -> List[bytes]:
236242def ip_addresses_by_version(
237243self, version: IPVersion
238244 ) -> Union[List[ipaddress.IPv4Address], List[ipaddress.IPv6Address], List[ipaddress._BaseAddress]]:
239-"""List ip_address objects matching IP version."""
245+"""List ip_address objects matching IP version.
246+247+ Addresses are guaranteed to be returned in LIFO (last in, first out)
248+ order with IPv4 addresses first and IPv6 addresses second.
249+250+ This means the first address will always be the most recently added
251+ address of the given IP version.
252+ """
240253if version == IPVersion.V4Only:
241254return self._ipv4_addresses
242255if version == IPVersion.V6Only:
243256return self._ipv6_addresses
244257return [*self._ipv4_addresses, *self._ipv6_addresses]
245258246259def parsed_addresses(self, version: IPVersion = IPVersion.All) -> List[str]:
247-"""List addresses in their parsed string form."""
248-result = self.addresses_by_version(version)
249-return [
250-socket.inet_ntop(socket.AF_INET6 if _is_v6_address(addr) else socket.AF_INET, addr)
251-for addr in result
252- ]
260+"""List addresses in their parsed string form.
261+262+ Addresses are guaranteed to be returned in LIFO (last in, first out)
263+ order with IPv4 addresses first and IPv6 addresses second.
264+265+ This means the first address will always be the most recently added
266+ address of the given IP version.
267+ """
268+return [str(addr) for addr in self.ip_addresses_by_version(version)]
253269254270def parsed_scoped_addresses(self, version: IPVersion = IPVersion.All) -> List[str]:
255271"""Equivalent to parsed_addresses, with the exception that IPv6 Link-Local
256272 addresses are qualified with %<interface_index> when available
273+274+ Addresses are guaranteed to be returned in LIFO (last in, first out)
275+ order with IPv4 addresses first and IPv6 addresses second.
276+277+ This means the first address will always be the most recently added
278+ address of the given IP version.
257279 """
258280if self.interface_index is None:
259281return self.parsed_addresses(version)
260-261-def is_link_local(addr_str: str) -> Any:
262-addr = _cached_ip_addresses(addr_str)
263-return addr.version == 6 and addr.is_link_local
264-265-ll_addrs = list(filter(is_link_local, self.parsed_addresses(version)))
266-other_addrs = list(filter(lambda addr: not is_link_local(addr), self.parsed_addresses(version)))
267-return [f"{addr}%{self.interface_index}" for addr in ll_addrs] + other_addrs
282+return [
283+f"{addr}%{self.interface_index}" if addr.version == 6 and addr.is_link_local else str(addr)
284+for addr in self.ip_addresses_by_version(version)
285+ ]
268286269287def _set_properties(self, properties: Dict) -> None:
270288"""Sets properties and text of this info from a dictionary"""
@@ -399,13 +417,13 @@ def dns_addresses(
399417return [
400418DNSAddress(
401419self.server,
402-_TYPE_AAAA if _is_v6_address(address) else _TYPE_A,
420+_TYPE_AAAA if address.version == 6 else _TYPE_A,
403421_CLASS_IN | _CLASS_UNIQUE,
404422override_ttl if override_ttl is not None else self.host_ttl,
405-address,
423+address.packed,
406424created=created,
407425 )
408-for address in self.addresses_by_version(version)
426+for address in self.ip_addresses_by_version(version)
409427 ]
410428411429def dns_pointer(self, override_ttl: Optional[int] = None, created: Optional[float] = None) -> DNSPointer: