Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-zeroconf for openSUSE:Factory checked in at 2021-10-27 22:21:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-zeroconf (Old) and /work/SRC/openSUSE:Factory/.python-zeroconf.new.1890 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-zeroconf" Wed Oct 27 22:21:03 2021 rev:26 rq:927595 version:0.36.9 Changes: -------- --- /work/SRC/openSUSE:Factory/python-zeroconf/python-zeroconf.changes 2021-10-19 23:04:37.857294842 +0200 +++ /work/SRC/openSUSE:Factory/.python-zeroconf.new.1890/python-zeroconf.changes 2021-10-27 22:21:15.771200419 +0200 @@ -1,0 +2,6 @@ +Tue Oct 26 20:31:03 UTC 2021 - Dirk M??ller <dmuel...@suse.com> + +- update to 0.36.9: + * Ensure ServiceInfo orders newest addresses first + +------------------------------------------------------------------- Old: ---- python-zeroconf-0.36.8.obscpio New: ---- python-zeroconf-0.36.9.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-zeroconf.spec ++++++ --- /var/tmp/diff_new_pack.SWfphL/_old 2021-10-27 22:21:16.335200708 +0200 +++ /var/tmp/diff_new_pack.SWfphL/_new 2021-10-27 22:21:16.339200710 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-zeroconf -Version: 0.36.8 +Version: 0.36.9 Release: 0 Summary: Pure Python Multicast DNS Service Discovery Library (Bonjour/Avahi compatible) License: LGPL-2.0-only ++++++ _service ++++++ --- /var/tmp/diff_new_pack.SWfphL/_old 2021-10-27 22:21:16.367200724 +0200 +++ /var/tmp/diff_new_pack.SWfphL/_new 2021-10-27 22:21:16.367200724 +0200 @@ -2,8 +2,8 @@ <service name="obs_scm" mode="disabled"> <param name="url">https://github.com/jstasiak/python-zeroconf</param> <param name="scm">git</param> - <param name="revision">0.36.8</param> - <param name="version">0.36.8</param> + <param name="revision">0.36.9</param> + <param name="version">0.36.9</param> </service> <service name="set_version" mode="disabled"/> <service mode="buildtime" name="tar" /> ++++++ python-zeroconf-0.36.8.obscpio -> python-zeroconf-0.36.9.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-zeroconf-0.36.8/README.rst new/python-zeroconf-0.36.9/README.rst --- old/python-zeroconf-0.36.8/README.rst 2021-10-11 01:04:21.000000000 +0200 +++ new/python-zeroconf-0.36.9/README.rst 2021-10-23 01:14:47.000000000 +0200 @@ -138,6 +138,14 @@ Changelog ========= +0.36.9 +====== + +* Ensure ServiceInfo orders newest addresess first (#1012) @bdraco + + This change effectively restored the behavior before 1s cache flush + expire behavior described in rfc6762 section 10.2 was added for callers that rely on this. + 0.36.8 ====== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-zeroconf-0.36.8/setup.cfg new/python-zeroconf-0.36.9/setup.cfg --- old/python-zeroconf-0.36.8/setup.cfg 2021-10-11 01:04:21.000000000 +0200 +++ new/python-zeroconf-0.36.9/setup.cfg 2021-10-23 01:14:47.000000000 +0200 @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.36.8 +current_version = 0.36.9 commit = True tag = True tag_name = {new_version} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-zeroconf-0.36.8/tests/services/test_info.py new/python-zeroconf-0.36.9/tests/services/test_info.py --- old/python-zeroconf-0.36.8/tests/services/test_info.py 2021-10-11 01:04:21.000000000 +0200 +++ new/python-zeroconf-0.36.9/tests/services/test_info.py 2021-10-23 01:14:47.000000000 +0200 @@ -560,7 +560,27 @@ # This test uses asyncio because it needs to access the cache directly # which is not threadsafe @pytest.mark.asyncio -async def test_multiple_a_addresses(): +async def test_multiple_a_addresses_newest_address_first(): + """Test that info.addresses returns the newest seen address first.""" + type_ = "_http._tcp.local." + registration_name = "multiarec.%s" % type_ + desc = {'path': '/~paulsm/'} + aiozc = AsyncZeroconf(interfaces=['127.0.0.1']) + cache = aiozc.zeroconf.cache + host = "multahost.local." + record1 = r.DNSAddress(host, const._TYPE_A, const._CLASS_IN, 1000, b'\x7f\x00\x00\x01') + record2 = r.DNSAddress(host, const._TYPE_A, const._CLASS_IN, 1000, b'\x7f\x00\x00\x02') + cache.async_add_records([record1, record2]) + + # New kwarg way + info = ServiceInfo(type_, registration_name, 80, 0, 0, desc, host) + info.load_from_cache(aiozc.zeroconf) + assert info.addresses == [b'\x7f\x00\x00\x02', b'\x7f\x00\x00\x01'] + await aiozc.async_close() + + +@pytest.mark.asyncio +async def test_invalid_a_addresses(caplog): type_ = "_http._tcp.local." registration_name = "multiarec.%s" % type_ desc = {'path': '/~paulsm/'} @@ -574,7 +594,9 @@ # New kwarg way info = ServiceInfo(type_, registration_name, 80, 0, 0, desc, host) info.load_from_cache(aiozc.zeroconf) - assert set(info.addresses) == set([b'a', b'b']) + assert not info.addresses + assert "Encountered invalid address while processing record" in caplog.text + await aiozc.async_close() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-zeroconf-0.36.8/tests/test_exceptions.py new/python-zeroconf-0.36.9/tests/test_exceptions.py --- old/python-zeroconf-0.36.8/tests/test_exceptions.py 2021-10-11 01:04:21.000000000 +0200 +++ new/python-zeroconf-0.36.9/tests/test_exceptions.py 2021-10-23 01:14:47.000000000 +0200 @@ -141,11 +141,11 @@ name = "xxxyyy" registration_name = f"{name}.{type_}" - bad = ('127.0.0.1', '::1', 42) + bad = (b'127.0.0.1', b'::1') for addr in bad: self.assertRaisesRegex( TypeError, - 'Addresses must be bytes', + 'Addresses must either ', ServiceInfo, type_, registration_name, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-zeroconf-0.36.8/zeroconf/__init__.py new/python-zeroconf-0.36.9/zeroconf/__init__.py --- old/python-zeroconf-0.36.8/zeroconf/__init__.py 2021-10-11 01:04:21.000000000 +0200 +++ new/python-zeroconf-0.36.9/zeroconf/__init__.py 2021-10-23 01:14:47.000000000 +0200 @@ -79,7 +79,7 @@ __author__ = 'Paul Scott-Murphy, William McBrine' __maintainer__ = 'Jakub Stasiak <ja...@stasiak.at>' -__version__ = '0.36.8' +__version__ = '0.36.9' __license__ = 'LGPL' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-zeroconf-0.36.8/zeroconf/_services/info.py new/python-zeroconf-0.36.9/zeroconf/_services/info.py --- old/python-zeroconf-0.36.8/zeroconf/_services/info.py 2021-10-11 01:04:21.000000000 +0200 +++ new/python-zeroconf-0.36.9/zeroconf/_services/info.py 2021-10-23 01:14:47.000000000 +0200 @@ -27,6 +27,7 @@ from .._dns import DNSAddress, DNSPointer, DNSQuestionType, DNSRecord, DNSService, DNSText from .._exceptions import BadTypeInNameException +from .._logger import log from .._protocol.outgoing import DNSOutgoing from .._updates import RecordUpdate, RecordUpdateListener from .._utils.asyncio import get_running_loop, run_coro_with_timeout @@ -124,19 +125,12 @@ self.type = type_ self._name = name self.key = name.lower() + self._ipv4_addresses: List[ipaddress.IPv4Address] = [] + self._ipv6_addresses: List[ipaddress.IPv6Address] = [] if addresses is not None: - self._addresses = addresses + self.addresses = addresses elif parsed_addresses is not None: - self._addresses = [_encode_address(a) for a in parsed_addresses] - else: - self._addresses = [] - # This results in an ugly error when registering, better check now - invalid = [a for a in self._addresses if not isinstance(a, bytes) or len(a) not in (4, 16)] - if invalid: - raise TypeError( - 'Addresses must be bytes, got %s. Hint: convert string addresses ' - 'with socket.inet_pton' % invalid - ) + self.addresses = [_encode_address(a) for a in parsed_addresses] self.port = port self.weight = weight self.priority = priority @@ -178,7 +172,21 @@ This replaces all currently stored addresses, both IPv4 and IPv6. """ - self._addresses = value + self._ipv4_addresses.clear() + self._ipv6_addresses.clear() + + for address in value: + try: + addr = ipaddress.ip_address(address) + except ValueError: + raise TypeError( + "Addresses must either be IPv4 or IPv6 strings, bytes, or integers;" + f" got {address}. Hint: convert string addresses with socket.inet_pton" # type: ignore + ) + if addr.version == 4: + self._ipv4_addresses.append(addr) + else: + self._ipv6_addresses.append(addr) @property def properties(self) -> Dict: @@ -194,10 +202,13 @@ def addresses_by_version(self, version: IPVersion) -> List[bytes]: """List addresses matching IP version.""" if version == IPVersion.V4Only: - return [addr for addr in self._addresses if not _is_v6_address(addr)] + return [addr.packed for addr in self._ipv4_addresses] if version == IPVersion.V6Only: - return list(filter(_is_v6_address, self._addresses)) - return self._addresses + return [addr.packed for addr in self._ipv6_addresses] + return [ + *(addr.packed for addr in self._ipv4_addresses), + *(addr.packed for addr in self._ipv6_addresses), + ] def parsed_addresses(self, version: IPVersion = IPVersion.All) -> List[str]: """List addresses in their parsed string form.""" @@ -220,7 +231,7 @@ ll_addrs = list(filter(is_link_local, self.parsed_addresses(version))) other_addrs = list(filter(lambda addr: not is_link_local(addr), self.parsed_addresses(version))) - return ["{}%{}".format(addr, self.interface_index) for addr in ll_addrs] + other_addrs + return [f"{addr}%{self.interface_index}" for addr in ll_addrs] + other_addrs def _set_properties(self, properties: Dict) -> None: """Sets properties and text of this info from a dictionary""" @@ -315,9 +326,20 @@ return if isinstance(record, DNSAddress): - if record.key == self.server_key and record.address not in self._addresses: - self._addresses.append(record.address) - if record.type is _TYPE_AAAA and ipaddress.IPv6Address(record.address).is_link_local: + if record.key != self.server_key: + return + try: + ip_addr = ipaddress.ip_address(record.address) + except ValueError as ex: + log.warning("Encountered invalid address while processing %s: %s", record, ex) + return + if ip_addr.version == 4: + if ip_addr not in self._ipv4_addresses: + self._ipv4_addresses.insert(0, ip_addr) + return + if ip_addr not in self._ipv6_addresses: + self._ipv6_addresses.insert(0, ip_addr) + if ip_addr.is_link_local: self.interface_index = record.scope_id return @@ -422,7 +444,7 @@ @property def _is_complete(self) -> bool: """The ServiceInfo has all expected properties.""" - return not (self.text is None or not self._addresses) + return bool(self.text is not None and (self._ipv4_addresses or self._ipv6_addresses)) def request( self, zc: 'Zeroconf', timeout: float, question_type: Optional[DNSQuestionType] = None @@ -494,10 +516,10 @@ def __repr__(self) -> str: """String representation""" - return '%s(%s)' % ( + return '{}({})'.format( type(self).__name__, ', '.join( - '%s=%r' % (name, getattr(self, name)) + '{}={!r}'.format(name, getattr(self, name)) for name in ( 'type', 'name', ++++++ python-zeroconf.obsinfo ++++++ --- /var/tmp/diff_new_pack.SWfphL/_old 2021-10-27 22:21:16.515200801 +0200 +++ /var/tmp/diff_new_pack.SWfphL/_new 2021-10-27 22:21:16.515200801 +0200 @@ -1,5 +1,5 @@ name: python-zeroconf -version: 0.36.8 -mtime: 1633907061 -commit: 61275efd05688a61d656b43125b01a5d588f1dba +version: 0.36.9 +mtime: 1634944487 +commit: d92d3d030558c1b81b2e35f701b585f4b48fa99a