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 2022-01-10 23:53:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-zeroconf (Old)
and /work/SRC/openSUSE:Factory/.python-zeroconf.new.1892 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-zeroconf"
Mon Jan 10 23:53:19 2022 rev:29 rq:945269 version:0.38.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-zeroconf/python-zeroconf.changes
2021-12-02 02:25:12.420617506 +0100
+++
/work/SRC/openSUSE:Factory/.python-zeroconf.new.1892/python-zeroconf.changes
2022-01-10 23:53:46.276813170 +0100
@@ -1,0 +2,9 @@
+Mon Jan 3 10:29:30 UTC 2022 - Dirk M??ller <[email protected]>
+
+- update to 0.38.1:
+ * Dropped Python 3.6 support
+ * Handle Service types that end with another service type
+ * Improve performance of query scheduler
+ * Avoid linear type searches in ServiceBrowsers
+
+-------------------------------------------------------------------
Old:
----
python-zeroconf-0.37.0.obscpio
New:
----
python-zeroconf-0.38.1.obscpio
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-zeroconf.spec ++++++
--- /var/tmp/diff_new_pack.494Uhp/_old 2022-01-10 23:53:47.296814064 +0100
+++ /var/tmp/diff_new_pack.494Uhp/_new 2022-01-10 23:53:47.300814068 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-zeroconf
#
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,8 +18,9 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
+%define skip_python36 1
Name: python-zeroconf
-Version: 0.37.0
+Version: 0.38.1
Release: 0
Summary: Pure Python Multicast DNS Service Discovery Library
(Bonjour/Avahi compatible)
License: LGPL-2.0-only
++++++ _service ++++++
--- /var/tmp/diff_new_pack.494Uhp/_old 2022-01-10 23:53:47.328814092 +0100
+++ /var/tmp/diff_new_pack.494Uhp/_new 2022-01-10 23:53:47.332814095 +0100
@@ -2,8 +2,9 @@
<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.37.0</param>
- <param name="version">0.37.0</param>
+ <param name="revision">0.38.1</param>
+ <param name="versionformat">@PARENT_TAG@</param>
+ <param name="versionrewrite-pattern">(.*)</param>
</service>
<service name="set_version" mode="disabled"/>
<service mode="buildtime" name="tar" />
++++++ python-zeroconf-0.37.0.obscpio -> python-zeroconf-0.38.1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/.github/workflows/ci.yml
new/python-zeroconf-0.38.1/.github/workflows/ci.yml
--- old/python-zeroconf-0.37.0/.github/workflows/ci.yml 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/.github/workflows/ci.yml 2021-12-24
03:47:53.000000000 +0100
@@ -14,7 +14,7 @@
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
- python-version: [3.6, 3.7, 3.8, 3.9, "3.10", "pypy-3.6", "pypy-3.7"]
+ python-version: [3.7, 3.8, 3.9, "3.10", "pypy-3.7"]
include:
- os: ubuntu-latest
venvcmd: . env/bin/activate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/README.rst
new/python-zeroconf-0.38.1/README.rst
--- old/python-zeroconf-0.37.0/README.rst 2021-11-18 21:30:53.000000000
+0100
+++ new/python-zeroconf-0.38.1/README.rst 2021-12-24 03:47:53.000000000
+0100
@@ -44,8 +44,8 @@
Python compatibility
--------------------
-* CPython 3.6+
-* PyPy3 7.2+
+* CPython 3.7+
+* PyPy3.7 7.3+
Versioning
----------
@@ -138,6 +138,21 @@
Changelog
=========
+0.38.1
+======
+
+* Improve performance of query scheduler (#1043) @bdraco
+* Avoid linear type searches in ServiceBrowsers (#1044) @bdraco
+
+0.38.0
+======
+
+* Handle Service types that end with another service type (#1041) @apworks1
+
+Backwards incompatible:
+
+* Dropped Python 3.6 support (#1009) @bdraco
+
0.37.0
======
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/setup.cfg
new/python-zeroconf-0.38.1/setup.cfg
--- old/python-zeroconf-0.37.0/setup.cfg 2021-11-18 21:30:53.000000000
+0100
+++ new/python-zeroconf-0.38.1/setup.cfg 2021-12-24 03:47:53.000000000
+0100
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 0.37.0
+current_version = 0.38.1
commit = True
tag = True
tag_name = {new_version}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-zeroconf-0.37.0/tests/services/test_browser.py
new/python-zeroconf-0.38.1/tests/services/test_browser.py
--- old/python-zeroconf-0.37.0/tests/services/test_browser.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/services/test_browser.py 2021-12-24
03:47:53.000000000 +0100
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
""" Unit tests for zeroconf._services.browser. """
@@ -682,7 +681,7 @@
info_service = ServiceInfo(
type_,
- '%s.%s' % (name, type_),
+ f'{name}.{type_}',
80,
0,
0,
@@ -902,7 +901,7 @@
now = current_time_millis()
for i in range(120):
name = f"_hap{i}._tcp._local."
- questions_with_known_answers[DNSQuestion(name, const._TYPE_PTR,
const._CLASS_IN)] = set(
+ questions_with_known_answers[DNSQuestion(name, const._TYPE_PTR,
const._CLASS_IN)] = {
DNSPointer(
name,
const._TYPE_PTR,
@@ -911,7 +910,7 @@
f"zoo{counter}.{name}",
)
for counter in range(i)
- )
+ }
outs = _services_browser._group_ptr_queries_with_known_answers(now, True,
questions_with_known_answers)
for out in outs:
packets = out.packets()
@@ -937,7 +936,7 @@
10000,
f'known-to-other.{name}',
)
- other_known_answers = set([answer])
+ other_known_answers = {answer}
zc.question_history.add_question_at_time(question, now,
other_known_answers)
assert zc.question_history.suppresses(question, now, other_known_answers)
@@ -976,7 +975,7 @@
@pytest.mark.asyncio
async def test_query_scheduler():
delay = const._BROWSER_TIME
- types_ = set(["_hap._tcp.local.", "_http._tcp.local."])
+ types_ = {"_hap._tcp.local.", "_http._tcp.local."}
query_scheduler = _services_browser.QueryScheduler(types_, delay, (0, 0))
now = current_time_millis()
@@ -984,8 +983,8 @@
# Test query interval is increasing
assert query_scheduler.millis_to_wait(now - 1) == 1
- assert query_scheduler.millis_to_wait(now) is 0
- assert query_scheduler.millis_to_wait(now + 1) is 0
+ assert query_scheduler.millis_to_wait(now) == 0
+ assert query_scheduler.millis_to_wait(now + 1) == 0
assert set(query_scheduler.process_ready_types(now)) == types_
assert set(query_scheduler.process_ready_types(now)) == set()
@@ -1013,8 +1012,91 @@
assert set(query_scheduler.process_ready_types(now + delay * 15)) == set()
# Test if we reschedule 1 second later... and its ready for processing
- assert set(query_scheduler.process_ready_types(now + delay * 16)) ==
set(["_hap._tcp.local."])
+ assert set(query_scheduler.process_ready_types(now + delay * 16)) ==
{"_hap._tcp.local."}
assert query_scheduler.millis_to_wait(now) == pytest.approx(delay * 31,
0.00001)
assert set(query_scheduler.process_ready_types(now + delay * 20)) == set()
- assert set(query_scheduler.process_ready_types(now + delay * 31)) ==
set(["_http._tcp.local."])
+ assert set(query_scheduler.process_ready_types(now + delay * 31)) ==
{"_http._tcp.local."}
+
+
+def test_service_browser_matching():
+ """Test that the ServiceBrowser matching does not match partial names."""
+
+ # instantiate a zeroconf instance
+ zc = Zeroconf(interfaces=['127.0.0.1'])
+ # start a browser
+ type_ = "_http._tcp.local."
+ registration_name = "xxxyyy.%s" % type_
+ not_match_type_ = "_asustor-looksgood_http._tcp.local."
+ not_match_registration_name = "xxxyyy.%s" % not_match_type_
+ callbacks = []
+
+ class MyServiceListener(r.ServiceListener):
+ def add_service(self, zc, type_, name) -> None:
+ nonlocal callbacks
+ if name == registration_name:
+ callbacks.append(("add", type_, name))
+
+ def remove_service(self, zc, type_, name) -> None:
+ nonlocal callbacks
+ if name == registration_name:
+ callbacks.append(("remove", type_, name))
+
+ def update_service(self, zc, type_, name) -> None:
+ nonlocal callbacks
+ if name == registration_name:
+ callbacks.append(("update", type_, name))
+
+ listener = MyServiceListener()
+
+ browser = r.ServiceBrowser(zc, type_, None, listener)
+
+ desc = {'path': '/~paulsm/'}
+ address_parsed = "10.0.1.2"
+ address = socket.inet_aton(address_parsed)
+ info = ServiceInfo(type_, registration_name, 80, 0, 0, desc,
"ash-2.local.", addresses=[address])
+ should_not_match = ServiceInfo(
+ not_match_type_, not_match_registration_name, 80, 0, 0, desc,
"ash-2.local.", addresses=[address]
+ )
+
+ def mock_incoming_msg(records) -> r.DNSIncoming:
+ generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE)
+ for record in records:
+ generated.add_answer_at_time(record, 0)
+ return r.DNSIncoming(generated.packets()[0])
+
+ _inject_response(
+ zc,
+ mock_incoming_msg([info.dns_pointer(), info.dns_service(),
info.dns_text(), *info.dns_addresses()]),
+ )
+ _inject_response(
+ zc,
+ mock_incoming_msg(
+ [
+ should_not_match.dns_pointer(),
+ should_not_match.dns_service(),
+ should_not_match.dns_text(),
+ *should_not_match.dns_addresses(),
+ ]
+ ),
+ )
+ time.sleep(0.2)
+ info.port = 400
+ _inject_response(
+ zc,
+ mock_incoming_msg([info.dns_service()]),
+ )
+ should_not_match.port = 400
+ _inject_response(
+ zc,
+ mock_incoming_msg([should_not_match.dns_service()]),
+ )
+ time.sleep(0.2)
+
+ assert callbacks == [
+ ('add', type_, registration_name),
+ ('update', type_, registration_name),
+ ]
+ browser.cancel()
+
+ zc.close()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/tests/services/test_info.py
new/python-zeroconf-0.38.1/tests/services/test_info.py
--- old/python-zeroconf-0.37.0/tests/services/test_info.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/services/test_info.py 2021-12-24
03:47:53.000000000 +0100
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
""" Unit tests for zeroconf._services.info. """
@@ -607,7 +606,7 @@
desc = {'path': '/~paulsm/'}
type_ = "_homeassistant._tcp.local."
name = "MyTestHome"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
ipv4 = socket.inet_aton("10.0.1.2")
ipv6 = socket.inet_pton(socket.AF_INET6, "2001:db8::1")
info = ServiceInfo(type_, registration_name, 80, 0, 0, desc,
"ash-2.local.", addresses=[ipv4, ipv6])
@@ -627,7 +626,7 @@
name = "MyTestHome"
info_service = ServiceInfo(
type_,
- '%s.%s' % (name, type_),
+ f'{name}.{type_}',
80,
0,
0,
@@ -649,7 +648,7 @@
with pytest.raises(TypeError):
info_service = ServiceInfo(
type_,
- '%s.%s' % (name, type_),
+ f'{name}.{type_}',
80,
0,
0,
@@ -661,7 +660,7 @@
info_service = ServiceInfo(
type_,
- '%s.%s' % (name, type_),
+ f'{name}.{type_}',
80,
0,
0,
@@ -680,12 +679,12 @@
addresses = [socket.inet_aton("10.0.1.2")]
server_name = "ash-2.local."
info_service = ServiceInfo(
- type_, '%s.%s' % (name, type_), 80, 0, 0, {b'path': b'/~paulsm/'},
server_name, addresses=addresses
+ type_, f'{name}.{type_}', 80, 0, 0, {b'path': b'/~paulsm/'},
server_name, addresses=addresses
)
assert info_service.dns_text().text == b'\x0epath=/~paulsm/'
info_service = ServiceInfo(
type_,
- '%s.%s' % (name, type_),
+ f'{name}.{type_}',
80,
0,
0,
@@ -696,7 +695,7 @@
assert info_service.dns_text().text == b'\x0epath=/~paulsm/'
info_service = ServiceInfo(
type_,
- '%s.%s' % (name, type_),
+ f'{name}.{type_}',
80,
0,
0,
@@ -707,7 +706,7 @@
assert info_service.dns_text().text == b'\x0epath=/~paulsm/'
info_service = ServiceInfo(
type_,
- '%s.%s' % (name, type_),
+ f'{name}.{type_}',
80,
0,
0,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/python-zeroconf-0.37.0/tests/services/test_registry.py
new/python-zeroconf-0.38.1/tests/services/test_registry.py
--- old/python-zeroconf-0.37.0/tests/services/test_registry.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/services/test_registry.py 2021-12-24
03:47:53.000000000 +0100
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
"""Unit tests for zeroconf._services.registry."""
@@ -15,7 +14,7 @@
def test_only_register_once(self):
type_ = "_test-srvc-type._tcp.local."
name = "xxxyyy"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
desc = {'path': '/~paulsm/'}
info = ServiceInfo(
@@ -32,8 +31,8 @@
type_ = "_test-srvc-type._tcp.local."
name = "xxxyyy"
name2 = "xxxyyy2"
- registration_name = "%s.%s" % (name, type_)
- registration_name2 = "%s.%s" % (name2, type_)
+ registration_name = f"{name}.{type_}"
+ registration_name2 = f"{name2}.{type_}"
desc = {'path': '/~paulsm/'}
info = ServiceInfo(
@@ -61,7 +60,7 @@
"""
type_ = "_test-srvc-type._tcp.local."
name = "xxxyyy"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
desc = {'path': '/~paulsm/'}
info = ServiceInfo(
@@ -77,7 +76,7 @@
def test_lookups(self):
type_ = "_test-srvc-type._tcp.local."
name = "xxxyyy"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
desc = {'path': '/~paulsm/'}
info = ServiceInfo(
@@ -96,7 +95,7 @@
def test_lookups_upper_case_by_lower_case(self):
type_ = "_test-SRVC-type._tcp.local."
name = "Xxxyyy"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
desc = {'path': '/~paulsm/'}
info = ServiceInfo(
@@ -115,7 +114,7 @@
def test_lookups_lower_case_by_upper_case(self):
type_ = "_test-srvc-type._tcp.local."
name = "xxxyyy"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
desc = {'path': '/~paulsm/'}
info = ServiceInfo(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/tests/services/test_types.py
new/python-zeroconf-0.38.1/tests/services/test_types.py
--- old/python-zeroconf-0.37.0/tests/services/test_types.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/services/test_types.py 2021-12-24
03:47:53.000000000 +0100
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
"""Unit tests for zeroconf._services.types."""
@@ -36,7 +35,7 @@
type_ = "_test-listen-type._tcp.local."
name = "xxxyyy"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
zeroconf_registrar = Zeroconf(interfaces=['127.0.0.1'])
desc = {'path': '/~paulsm/'}
@@ -72,7 +71,7 @@
type_ = "_test-listenv6rec-type._tcp.local."
name = "xxxyyy"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
addr = "2606:2800:220:1:248:1893:25c8:1946" # example.com
zeroconf_registrar = Zeroconf(interfaces=['127.0.0.1'])
@@ -109,7 +108,7 @@
type_ = "_test-listenv6ip-type._tcp.local."
name = "xxxyyy"
- registration_name = "%s.%s" % (name, type_)
+ registration_name = f"{name}.{type_}"
addr = "2606:2800:220:1:248:1893:25c8:1946" # example.com
zeroconf_registrar = Zeroconf(ip_version=r.IPVersion.V6Only)
@@ -145,8 +144,8 @@
type_ = "_listen._tcp.local."
name = "xxxyyy"
# Note: discovery returns only DNS-SD type not subtype
- discovery_type = "%s.%s" % (subtype_, type_)
- registration_name = "%s.%s" % (name, type_)
+ discovery_type = f"{subtype_}.{type_}"
+ registration_name = f"{name}.{type_}"
zeroconf_registrar = Zeroconf(interfaces=['127.0.0.1'])
desc = {'path': '/~paulsm/'}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/tests/test_asyncio.py
new/python-zeroconf-0.38.1/tests/test_asyncio.py
--- old/python-zeroconf-0.37.0/tests/test_asyncio.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/test_asyncio.py 2021-12-24
03:47:53.000000000 +0100
@@ -923,7 +923,7 @@
# Increase simulated time shift by 1/4 of the TTL in seconds
time_offset += expected_ttl / 4
now = _new_current_time_millis()
- browser.reschedule_type(type_, now)
+ browser.reschedule_type(type_, now, now)
sleep_count += 1
await asyncio.wait_for(got_query.wait(), 1)
got_query.clear()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/tests/test_exceptions.py
new/python-zeroconf-0.38.1/tests/test_exceptions.py
--- old/python-zeroconf-0.37.0/tests/test_exceptions.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/test_exceptions.py 2021-12-24
03:47:53.000000000 +0100
@@ -76,6 +76,8 @@
def test_good_instance_names(self):
assert r.service_type_name('.._x._tcp.local.') == '_x._tcp.local.'
+ assert r.service_type_name('x.y._http._tcp.local.') ==
'_http._tcp.local.'
+ assert r.service_type_name('1.2.3._mqtt._tcp.local.') ==
'_mqtt._tcp.local.'
assert r.service_type_name('x.sub._http._tcp.local.') ==
'_http._tcp.local.'
assert (
r.service_type_name('6d86f882b90facee9170ad3439d72a4d6ee9f511._zget._http._tcp.local.')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/tests/test_services.py
new/python-zeroconf-0.38.1/tests/test_services.py
--- old/python-zeroconf-0.37.0/tests/test_services.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/test_services.py 2021-12-24
03:47:53.000000000 +0100
@@ -38,12 +38,13 @@
class ListenerTest(unittest.TestCase):
def test_integration_with_listener_class(self):
+ sub_service_added = Event()
service_added = Event()
service_removed = Event()
- service_updated = Event()
- service_updated2 = Event()
+ sub_service_updated = Event()
+ duplicate_service_added = Event()
- subtype_name = "My special Subtype"
+ subtype_name = "_printer"
type_ = "_http._tcp.local."
subtype = subtype_name + "._sub." + type_
name = "UPPERxxxyyy??????"
@@ -58,21 +59,32 @@
service_removed.set()
def update_service(self, zeroconf, type, name):
- service_updated2.set()
+ pass
+
+ class DuplicateListener(r.ServiceListener):
+ def add_service(self, zeroconf, type, name):
+ duplicate_service_added.set()
+
+ def remove_service(self, zeroconf, type, name):
+ pass
+
+ def update_service(self, zeroconf, type, name):
+ pass
class MySubListener(r.ServiceListener):
def add_service(self, zeroconf, type, name):
+ sub_service_added.set()
pass
def remove_service(self, zeroconf, type, name):
pass
def update_service(self, zeroconf, type, name):
- service_updated.set()
+ sub_service_updated.set()
listener = MyListener()
zeroconf_browser = Zeroconf(interfaces=['127.0.0.1'])
- zeroconf_browser.add_service_listener(subtype, listener)
+ zeroconf_browser.add_service_listener(type_, listener)
properties = dict(
prop_none=None,
@@ -107,6 +119,11 @@
# short pause to allow multicast timers to expire
time.sleep(3)
+ zeroconf_browser.add_service_listener(type_,
DuplicateListener())
+ duplicate_service_added.wait(
+ 1
+ ) # Ensure a listener for the same type calls back right away
from cache
+
# clear the answer cache to force query
_clear_cache(zeroconf_browser)
@@ -160,7 +177,9 @@
# test TXT record update
sublistener = MySubListener()
- zeroconf_browser.add_service_listener(registration_name,
sublistener)
+
+ zeroconf_browser.add_service_listener(subtype, sublistener)
+
properties['prop_blank'] = b'an updated string'
desc.update(properties)
info_service = ServiceInfo(
@@ -174,8 +193,9 @@
addresses=[socket.inet_aton("10.0.1.2")],
)
zeroconf_registrar.update_service(info_service)
- service_updated.wait(1)
- assert service_updated.is_set()
+
+ sub_service_added.wait(1) # we cleared the cache above
+ assert sub_service_added.is_set()
info = zeroconf_browser.get_service_info(type_,
registration_name)
assert info is not None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/tests/utils/test_asyncio.py
new/python-zeroconf-0.38.1/tests/utils/test_asyncio.py
--- old/python-zeroconf-0.37.0/tests/utils/test_asyncio.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/utils/test_asyncio.py 2021-12-24
03:47:53.000000000 +0100
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
"""Unit tests for zeroconf._utils.asyncio."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/tests/utils/test_name.py
new/python-zeroconf-0.38.1/tests/utils/test_name.py
--- old/python-zeroconf-0.37.0/tests/utils/test_name.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/utils/test_name.py 2021-12-24
03:47:53.000000000 +0100
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
"""Unit tests for zeroconf._utils.name."""
@@ -24,3 +23,25 @@
nameutils.service_type_name(f"{long_name}._tivo-videostream._tcp.local.")
with pytest.raises(BadTypeInNameException):
nameutils.service_type_name(f"{long_name}._tivo-videostream._tcp.local.",
strict=False)
+
+
+def test_possible_types():
+ """Test possible types from name."""
+ assert nameutils.possible_types('.') == set()
+ assert nameutils.possible_types('local.') == set()
+ assert nameutils.possible_types('_tcp.local.') == set()
+ assert nameutils.possible_types('_test-srvc-type._tcp.local.') ==
{'_test-srvc-type._tcp.local.'}
+ assert nameutils.possible_types('_any._tcp.local.') == {'_any._tcp.local.'}
+ assert nameutils.possible_types('.._x._tcp.local.') == {'_x._tcp.local.'}
+ assert nameutils.possible_types('x.y._http._tcp.local.') ==
{'_http._tcp.local.'}
+ assert nameutils.possible_types('1.2.3._mqtt._tcp.local.') ==
{'_mqtt._tcp.local.'}
+ assert nameutils.possible_types('x.sub._http._tcp.local.') ==
{'_http._tcp.local.'}
+ assert
nameutils.possible_types('6d86f882b90facee9170ad3439d72a4d6ee9f511._zget._http._tcp.local.')
== {
+ '_http._tcp.local.',
+ '_zget._http._tcp.local.',
+ }
+ assert nameutils.possible_types('my._printer._sub._http._tcp.local.') == {
+ '_http._tcp.local.',
+ '_sub._http._tcp.local.',
+ '_printer._sub._http._tcp.local.',
+ }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/tests/utils/test_net.py
new/python-zeroconf-0.38.1/tests/utils/test_net.py
--- old/python-zeroconf-0.37.0/tests/utils/test_net.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/tests/utils/test_net.py 2021-12-24
03:47:53.000000000 +0100
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
"""Unit tests for zeroconf._utils.net."""
@@ -87,7 +86,7 @@
def test_add_multicast_member_socket_errors(errno, expected_result):
"""Test we handle socket errors when adding multicast members."""
if errno:
- setsockopt_mock = unittest.mock.Mock(side_effect=OSError(errno,
"Error: {}".format(errno)))
+ setsockopt_mock = unittest.mock.Mock(side_effect=OSError(errno,
f"Error: {errno}"))
else:
setsockopt_mock = unittest.mock.Mock()
fileno_mock = unittest.mock.PropertyMock(return_value=10)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/zeroconf/__init__.py
new/python-zeroconf-0.38.1/zeroconf/__init__.py
--- old/python-zeroconf-0.37.0/zeroconf/__init__.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/zeroconf/__init__.py 2021-12-24
03:47:53.000000000 +0100
@@ -79,7 +79,7 @@
__author__ = 'Paul Scott-Murphy, William McBrine'
__maintainer__ = 'Jakub Stasiak <[email protected]>'
-__version__ = '0.37.0'
+__version__ = '0.38.1'
__license__ = 'LGPL'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/zeroconf/_handlers.py
new/python-zeroconf-0.38.1/zeroconf/_handlers.py
--- old/python-zeroconf-0.37.0/zeroconf/_handlers.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/zeroconf/_handlers.py 2021-12-24
03:47:53.000000000 +0100
@@ -326,7 +326,7 @@
self._add_address_answers(question.name, answer_set,
known_answers, now, type_)
if type_ in (_TYPE_SRV, _TYPE_TXT, _TYPE_ANY):
- service = self.registry.async_get_info_name(question.name) #
type: ignore
+ service = self.registry.async_get_info_name(question.name)
if service is not None:
if type_ in (_TYPE_SRV, _TYPE_ANY):
# Add recommended additional answers according to
@@ -515,12 +515,12 @@
This function must be run from the event loop.
"""
now = current_time_millis()
- records: List[RecordUpdate] = []
- for question in questions:
- for record in self.cache.async_entries_with_name(question.name):
- if not record.is_expired(now) and question.answered_by(record):
- records.append(RecordUpdate(record, None))
-
+ records: List[RecordUpdate] = [
+ RecordUpdate(record, None)
+ for question in questions
+ for record in self.cache.async_entries_with_name(question.name)
+ if not record.is_expired(now) and question.answered_by(record)
+ ]
if not records:
return
listener.async_update_records(self.zc, now, records)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/zeroconf/_services/browser.py
new/python-zeroconf-0.38.1/zeroconf/_services/browser.py
--- old/python-zeroconf-0.37.0/zeroconf/_services/browser.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/zeroconf/_services/browser.py 2021-12-24
03:47:53.000000000 +0100
@@ -26,7 +26,7 @@
import threading
import warnings
from collections import OrderedDict
-from typing import Callable, Dict, List, Optional, Set, TYPE_CHECKING, Tuple,
Union, cast
+from typing import Callable, Dict, Iterable, List, Optional, Set,
TYPE_CHECKING, Tuple, Union, cast
from .._dns import DNSAddress, DNSPointer, DNSQuestion, DNSQuestionType,
DNSRecord
from .._logger import log
@@ -38,8 +38,7 @@
SignalRegistrationInterface,
)
from .._updates import RecordUpdate, RecordUpdateListener
-from .._utils.asyncio import get_best_available_queue
-from .._utils.name import service_type_name
+from .._utils.name import possible_types, service_type_name
from .._utils.time import current_time_millis, millis_to_seconds
from ..const import (
_BROWSER_BACKOFF_LIMIT,
@@ -145,11 +144,11 @@
for type_ in types_:
question = DNSQuestion(type_, _TYPE_PTR, _CLASS_IN)
question.unicast = qu_question
- known_answers = set(
+ known_answers = {
cast(DNSPointer, record)
for record in zc.cache.get_all_by_details(type_, _TYPE_PTR,
_CLASS_IN)
if not record.is_stale(now)
- )
+ }
if not qu_question and zc.question_history.suppresses(
question, now, cast(Set[DNSRecord], known_answers)
):
@@ -293,7 +292,7 @@
self._pending_handlers: OrderedDict[Tuple[str, str],
ServiceStateChange] = OrderedDict()
self._service_state_changed = Signal()
self.query_scheduler = QueryScheduler(self.types, delay,
_FIRST_QUERY_DELAY_RANDOM_INTERVAL)
- self.queue: Optional[queue.Queue] = None
+ self.queue: Optional[queue.SimpleQueue] = None
self.done = False
self._first_request: bool = True
self._next_send_timer: Optional[asyncio.TimerHandle] = None
@@ -325,9 +324,9 @@
def service_state_changed(self) -> SignalRegistrationInterface:
return self._service_state_changed.registration_interface
- def _record_matching_type(self, record: DNSRecord) -> Optional[str]:
- """Return the type if the record matches one of the types we are
browsing."""
- return next((type_ for type_ in self.types if
record.name.endswith(type_)), None)
+ def _names_matching_types(self, names: Iterable[str]) -> List[Tuple[str,
str]]:
+ """Return the type and name for records matching the types we are
browsing."""
+ return [(type_, name) for name in names for type_ in
self.types.intersection(possible_types(name))]
def _enqueue_callback(
self,
@@ -353,14 +352,13 @@
) -> None:
"""Process a single record update from a batch of updates."""
if isinstance(record, DNSPointer):
- if record.name not in self.types:
- return
- if old_record is None:
- self._enqueue_callback(ServiceStateChange.Added, record.name,
record.alias)
- elif record.is_expired(now):
- self._enqueue_callback(ServiceStateChange.Removed,
record.name, record.alias)
- else:
- self.reschedule_type(record.name,
record.get_expiration_time(_EXPIRE_REFRESH_TIME_PERCENT))
+ for type_ in self.types.intersection(possible_types(record.name)):
+ if old_record is None:
+ self._enqueue_callback(ServiceStateChange.Added, type_,
record.alias)
+ elif record.is_expired(now):
+ self._enqueue_callback(ServiceStateChange.Removed, type_,
record.alias)
+ else:
+ self.reschedule_type(type_, now,
record.get_expiration_time(_EXPIRE_REFRESH_TIME_PERCENT))
return
# If its expired or already exists in the cache it cannot be updated.
@@ -369,17 +367,14 @@
if isinstance(record, DNSAddress):
# Iterate through the DNSCache and callback any services that use
this address
- for service in
self.zc.cache.async_entries_with_server(record.name):
- type_ = self._record_matching_type(service)
- if type_:
- self._enqueue_callback(ServiceStateChange.Updated, type_,
service.name)
- break
-
+ for type_, name in self._names_matching_types(
+ {service.name for service in
self.zc.cache.async_entries_with_server(record.name)}
+ ):
+ self._enqueue_callback(ServiceStateChange.Updated, type_, name)
return
- type_ = self._record_matching_type(record)
- if type_:
- self._enqueue_callback(ServiceStateChange.Updated, type_,
record.name)
+ for type_, name in self._names_matching_types((record.name,)):
+ self._enqueue_callback(ServiceStateChange.Updated, type_, name)
def async_update_records(self, zc: 'Zeroconf', now: float, records:
List[RecordUpdate]) -> None:
"""Callback invoked by Zeroconf when new information arrives.
@@ -431,9 +426,8 @@
self._cancel_send_timer()
self.zc.async_remove_listener(self)
- def _generate_ready_queries(self, first_request: bool) ->
List[DNSOutgoing]:
+ def _generate_ready_queries(self, first_request: bool, now: float) ->
List[DNSOutgoing]:
"""Generate the service browser query for any type that is due."""
- now = current_time_millis()
ready_types = self.query_scheduler.process_ready_types(now)
if not ready_types:
return []
@@ -448,40 +442,40 @@
async def _async_start_query_sender(self) -> None:
"""Start scheduling queries."""
await self.zc.async_wait_for_start()
- self._async_send_ready_queries()
- self._async_schedule_next()
+ self._async_send_ready_queries_schedule_next()
def _cancel_send_timer(self) -> None:
"""Cancel the next send."""
if self._next_send_timer:
self._next_send_timer.cancel()
- def reschedule_type(self, type_: str, next_time: float) -> None:
+ def reschedule_type(self, type_: str, now: float, next_time: float) ->
None:
"""Reschedule a type to be refreshed in the future."""
if self.query_scheduler.reschedule_type(type_, next_time):
self._cancel_send_timer()
- self._async_schedule_next()
- self._async_send_ready_queries()
+ self._async_schedule_next(now)
+ self._async_send_ready_queries(now)
- def _async_send_ready_queries(self) -> None:
+ def _async_send_ready_queries(self, now: float) -> None:
"""Send any ready queries."""
- outs = self._generate_ready_queries(self._first_request)
+ outs = self._generate_ready_queries(self._first_request, now)
if outs:
self._first_request = False
for out in outs:
self.zc.async_send(out, addr=self.addr, port=self.port)
def _async_send_ready_queries_schedule_next(self) -> None:
- """Send ready queries and schedule next one."""
+ """Send ready queries and schedule next one checking for done first."""
if self.done or self.zc.done:
return
- self._async_send_ready_queries()
- self._async_schedule_next()
+ now = current_time_millis()
+ self._async_send_ready_queries(now)
+ self._async_schedule_next(now)
- def _async_schedule_next(self) -> None:
+ def _async_schedule_next(self, now: float) -> None:
"""Scheule the next time."""
assert self.zc.loop is not None
- delay =
millis_to_seconds(self.query_scheduler.millis_to_wait(current_time_millis()))
+ delay = millis_to_seconds(self.query_scheduler.millis_to_wait(now))
self._next_send_timer = self.zc.loop.call_later(delay,
self._async_send_ready_queries_schedule_next)
@@ -511,11 +505,11 @@
# Add the queue before the listener is installed in _setup
# to ensure that events run in the dedicated thread and do
# not block the event loop
- self.queue = get_best_available_queue()
+ self.queue = queue.SimpleQueue()
self.daemon = True
self.start()
zc.loop.call_soon_threadsafe(self._async_start)
- self.name = "zeroconf-ServiceBrowser-%s-%s" % (
+ self.name = "zeroconf-ServiceBrowser-{}-{}".format(
'-'.join([type_[:-7] for type_ in self.types]),
getattr(self, 'native_id', self.ident),
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/zeroconf/_utils/asyncio.py
new/python-zeroconf-0.38.1/zeroconf/_utils/asyncio.py
--- old/python-zeroconf-0.37.0/zeroconf/_utils/asyncio.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/zeroconf/_utils/asyncio.py 2021-12-24
03:47:53.000000000 +0100
@@ -23,8 +23,7 @@
import asyncio
import concurrent.futures
import contextlib
-import queue
-from typing import Any, Awaitable, Coroutine, List, Optional, Set, cast
+from typing import Any, Awaitable, Coroutine, Optional, Set
from .time import millis_to_seconds
from .._exceptions import EventLoopBlocked
@@ -36,13 +35,6 @@
_WAIT_FOR_LOOP_TASKS_TIMEOUT = 3 # Must be larger than _TASK_AWAIT_TIMEOUT
-def get_best_available_queue() -> queue.Queue:
- """Create the best available queue type."""
- if hasattr(queue, "SimpleQueue"):
- return queue.SimpleQueue() # type: ignore # pylint: disable=all
- return queue.Queue()
-
-
# Switch to asyncio.wait_for once https://bugs.python.org/issue39032 is fixed
async def wait_event_or_timeout(event: asyncio.Event, timeout: float) -> None:
"""Wait for an event or timeout."""
@@ -67,7 +59,7 @@
await event_wait
-async def _async_get_all_tasks(loop: asyncio.AbstractEventLoop) ->
List[asyncio.Task]:
+async def _async_get_all_tasks(loop: asyncio.AbstractEventLoop) ->
Set[asyncio.Task]:
"""Return all tasks running."""
await asyncio.sleep(0) # flush out any call_soon_threadsafe
# If there are multiple event loops running, all_tasks is not
@@ -75,10 +67,8 @@
# under PyPy so we have to try a few times.
for _ in range(3):
with contextlib.suppress(RuntimeError):
- if hasattr(asyncio, 'all_tasks'):
- return asyncio.all_tasks(loop) # type: ignore # pylint:
disable=no-member
- return asyncio.Task.all_tasks(loop) # type: ignore # pylint:
disable=no-member
- return []
+ return asyncio.all_tasks(loop)
+ return set()
async def _wait_for_loop_tasks(wait_tasks: Set[asyncio.Task]) -> None:
@@ -116,7 +106,7 @@
pending_tasks = set(
asyncio.run_coroutine_threadsafe(_async_get_all_tasks(loop),
loop).result(_GET_ALL_TASKS_TIMEOUT)
)
- pending_tasks -= set(task for task in pending_tasks if task.done())
+ pending_tasks -= {task for task in pending_tasks if task.done()}
if pending_tasks:
asyncio.run_coroutine_threadsafe(_wait_for_loop_tasks(pending_tasks),
loop).result(
_WAIT_FOR_LOOP_TASKS_TIMEOUT
@@ -128,10 +118,5 @@
def get_running_loop() -> Optional[asyncio.AbstractEventLoop]:
"""Check if an event loop is already running."""
with contextlib.suppress(RuntimeError):
- if hasattr(asyncio, "get_running_loop"):
- return cast(
- asyncio.AbstractEventLoop,
- asyncio.get_running_loop(), # type: ignore # pylint:
disable=no-member # noqa
- )
- return asyncio._get_running_loop() # pylint:
disable=no-member,protected-access
+ return asyncio.get_running_loop()
return None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/zeroconf/_utils/name.py
new/python-zeroconf-0.38.1/zeroconf/_utils/name.py
--- old/python-zeroconf-0.37.0/zeroconf/_utils/name.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/zeroconf/_utils/name.py 2021-12-24
03:47:53.000000000 +0100
@@ -20,6 +20,8 @@
USA
"""
+from typing import Set
+
from .._exceptions import BadTypeInNameException
from ..const import (
_HAS_ASCII_CONTROL_CHARS,
@@ -92,7 +94,7 @@
trailer = type_[-len(_LOCAL_TRAILER) + 1 :]
has_protocol = False
else:
- raise BadTypeInNameException("Type '%s' must end with '%s'" % (type_,
_LOCAL_TRAILER))
+ raise BadTypeInNameException(f"Type '{type_}' must end with
'{_LOCAL_TRAILER}'")
if strict or has_protocol:
service_name = remaining.pop()
@@ -155,3 +157,16 @@
)
return service_name + trailer
+
+
+def possible_types(name: str) -> Set[str]:
+ """Build a set of all possible types from a fully qualified name."""
+ labels = name.split('.')
+ label_count = len(labels)
+ types = set()
+ for count in range(label_count):
+ parts = labels[label_count - count - 4 :]
+ if not parts[0].startswith('_'):
+ break
+ types.add('.'.join(parts))
+ return types
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/python-zeroconf-0.37.0/zeroconf/_utils/net.py
new/python-zeroconf-0.38.1/zeroconf/_utils/net.py
--- old/python-zeroconf-0.37.0/zeroconf/_utils/net.py 2021-11-18
21:30:53.000000000 +0100
+++ new/python-zeroconf-0.38.1/zeroconf/_utils/net.py 2021-12-24
03:47:53.000000000 +0100
@@ -71,14 +71,14 @@
def get_all_addresses() -> List[str]:
- return list(set(addr.ip for iface in ifaddr.get_adapters() for addr in
iface.ips if addr.is_IPv4))
+ return list({addr.ip for iface in ifaddr.get_adapters() for addr in
iface.ips if addr.is_IPv4})
def get_all_addresses_v6() -> List[Tuple[Tuple[str, int, int], int]]:
# IPv6 multicast uses positive indexes for interfaces
# TODO: What about multi-address interfaces?
return list(
- set((addr.ip, iface.index) for iface in ifaddr.get_adapters() for addr
in iface.ips if addr.is_IPv6)
+ {(addr.ip, iface.index) for iface in ifaddr.get_adapters() for addr in
iface.ips if addr.is_IPv6}
)
@@ -203,7 +203,7 @@
try:
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, loop)
- except socket.error as e:
+ except OSError as e:
if bind_addr[0] != '' or get_errno(e) != errno.EINVAL: # Fails to
set on MacOS
raise
@@ -286,7 +286,7 @@
else:
_value = socket.inet_aton(_MDNS_ADDR) + socket.inet_aton(cast(str,
interface))
listen_socket.setsockopt(socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP, _value)
- except socket.error as e:
+ except OSError as e:
_errno = get_errno(e)
if _errno == errno.EADDRINUSE:
log.info(
++++++ python-zeroconf.obsinfo ++++++
--- /var/tmp/diff_new_pack.494Uhp/_old 2022-01-10 23:53:47.460814208 +0100
+++ /var/tmp/diff_new_pack.494Uhp/_new 2022-01-10 23:53:47.464814211 +0100
@@ -1,6 +1,5 @@
name: python-zeroconf
-version: 0.37.0
-mtime: 1637267453
-commit: 2996e642f6b1abba1dbb8242ccca4cd4b96696f6
-
+version: 0.38.1
+mtime: 1640314073
+commit: 6a11f24e1fc9d73f0dbb62efd834f17a9bd451c4