Hello community,

here is the log from the commit of package python-zeroconf for openSUSE:Factory 
checked in at 2020-07-21 15:51:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-zeroconf (Old)
 and      /work/SRC/openSUSE:Factory/.python-zeroconf.new.3592 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-zeroconf"

Tue Jul 21 15:51:05 2020 rev:14 rq:822073 version:0.28.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-zeroconf/python-zeroconf.changes  
2020-06-10 00:48:08.758902574 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-zeroconf.new.3592/python-zeroconf.changes    
    2020-07-21 15:54:22.188586543 +0200
@@ -1,0 +2,7 @@
+Tue Jul 21 10:13:44 UTC 2020 - Marketa Calabkova <[email protected]>
+
+- update to 0.28.0
+  * Added support for passing text addresses to ServiceInfo.
+  * Improved logging (includes fixing an incorrect logging call)
+
+-------------------------------------------------------------------

Old:
----
  python-zeroconf-0.27.1.tar.gz

New:
----
  python-zeroconf-0.28.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-zeroconf.spec ++++++
--- /var/tmp/diff_new_pack.gQAYn5/_old  2020-07-21 15:54:25.492590561 +0200
+++ /var/tmp/diff_new_pack.gQAYn5/_new  2020-07-21 15:54:25.492590561 +0200
@@ -19,19 +19,19 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-zeroconf
-Version:        0.27.1
+Version:        0.28.0
 Release:        0
 Summary:        Pure Python Multicast DNS Service Discovery Library 
(Bonjour/Avahi compatible)
 License:        LGPL-2.0-only
 Group:          Development/Languages/Python
 URL:            https://github.com/jstasiak/python-zeroconf
 Source:         
https://github.com/jstasiak/python-zeroconf/archive/%{version}.tar.gz#/%{name}-%{version}.tar.gz
-BuildRequires:  %{python_module ifaddr}
+BuildRequires:  %{python_module ifaddr >= 0.1.7}
 BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
-Requires:       python-ifaddr
+Requires:       python-ifaddr >= 0.1.7
 BuildArch:      noarch
 %python_subpackages
 

++++++ python-zeroconf-0.27.1.tar.gz -> python-zeroconf-0.28.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-zeroconf-0.27.1/README.rst 
new/python-zeroconf-0.28.0/README.rst
--- old/python-zeroconf-0.27.1/README.rst       2020-06-05 11:09:58.000000000 
+0200
+++ new/python-zeroconf-0.28.0/README.rst       2020-07-07 13:22:12.000000000 
+0200
@@ -134,6 +134,20 @@
 Changelog
 =========
 
+0.28.0
+======
+
+* Improved Windows support when using socket errno checks, thanks to Sandy 
Patterson.
+* Added support for passing text addresses to ServiceInfo.
+* Improved logging (includes fixing an incorrect logging call)
+* Improved Windows compatibility by using Adapter.index from ifaddr, thanks to 
PhilippSelenium.
+* Improved Windows compatibility by stopping using socket.if_nameindex.
+* Fixed an OS X edge case which should also eliminate a memory leak, thanks to 
Emil Styrke.
+
+Technically backwards incompatible:
+
+* ``ifaddr`` 0.1.7 or newer is required now.
+
 0.27.1
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-zeroconf-0.27.1/requirements-dev.txt 
new/python-zeroconf-0.28.0/requirements-dev.txt
--- old/python-zeroconf-0.27.1/requirements-dev.txt     2020-06-05 
11:09:58.000000000 +0200
+++ new/python-zeroconf-0.28.0/requirements-dev.txt     2020-07-07 
13:22:12.000000000 +0200
@@ -5,6 +5,7 @@
 flake8>=3.6.0
 flake8-import-order
 ifaddr
-pep8-naming!=0.6.0
+# 0.11.0 breaks things https://github.com/PyCQA/pep8-naming/issues/152
+pep8-naming!=0.6.0,!=0.11.0
 pytest
 pytest-cov
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-zeroconf-0.27.1/setup.py 
new/python-zeroconf-0.28.0/setup.py
--- old/python-zeroconf-0.27.1/setup.py 2020-06-05 11:09:58.000000000 +0200
+++ new/python-zeroconf-0.28.0/setup.py 2020-07-07 13:22:12.000000000 +0200
@@ -39,9 +39,10 @@
         'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: 3.6',
         'Programming Language :: Python :: 3.7',
+        'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: Implementation :: CPython',
         'Programming Language :: Python :: Implementation :: PyPy',
     ],
     keywords=['Bonjour', 'Avahi', 'Zeroconf', 'Multicast DNS', 'Service 
Discovery', 'mDNS'],
-    install_requires=['ifaddr'],
+    install_requires=['ifaddr>=0.1.7'],
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-zeroconf-0.27.1/zeroconf/__init__.py 
new/python-zeroconf-0.28.0/zeroconf/__init__.py
--- old/python-zeroconf-0.27.1/zeroconf/__init__.py     2020-06-05 
11:09:58.000000000 +0200
+++ new/python-zeroconf-0.28.0/zeroconf/__init__.py     2020-07-07 
13:22:12.000000000 +0200
@@ -25,7 +25,6 @@
 import ipaddress
 import itertools
 import logging
-import os
 import platform
 import re
 import select
@@ -43,7 +42,7 @@
 
 __author__ = 'Paul Scott-Murphy, William McBrine'
 __maintainer__ = 'Jakub Stasiak <[email protected]>'
-__version__ = '0.27.1'
+__version__ = '0.28.0'
 __license__ = 'LGPL'
 
 
@@ -190,7 +189,7 @@
     All = 2
 
 
-InterfacesType = Union[List[Union[str, int]], InterfaceChoice]
+InterfacesType = Union[List[Union[str, int, Tuple[Tuple[str, int, int], 
int]]], InterfaceChoice]
 
 
 @enum.unique
@@ -219,6 +218,12 @@
     return len(addr) == 16
 
 
+def _encode_address(address: str) -> bytes:
+    is_ipv6 = ':' in address
+    address_family = socket.AF_INET6 if is_ipv6 else socket.AF_INET
+    return socket.inet_pton(address_family, address)
+
+
 def service_type_name(type_: str, *, allow_underscores: bool = False) -> str:
     """
     Validate a fully qualified service name, instance or subtype. [rfc6763]
@@ -1696,8 +1701,8 @@
     * server: fully qualified name for service host (defaults to name)
     * host_ttl: ttl used for A/SRV records
     * other_ttl: ttl used for PTR/TXT records
-    * addresses: List of IP addresses as unsigned short (IPv4) or unsigned 128 
bit number (IPv6),
-      network byte order
+    * addresses and parsed_addresses: List of IP addresses (either as bytes, 
network byte order, or in parsed
+      form as text; at most one of those parameters can be provided)
 
     """
 
@@ -1718,14 +1723,20 @@
         host_ttl: int = _DNS_HOST_TTL,
         other_ttl: int = _DNS_OTHER_TTL,
         *,
-        addresses: Optional[List[bytes]] = None
+        addresses: Optional[List[bytes]] = None,
+        parsed_addresses: Optional[List[str]] = None
     ) -> None:
+        # Accept both none, or one, but not both.
+        if addresses is not None and parsed_addresses is not None:
+            raise TypeError("addresses and parsed_addresses cannot be provided 
together")
         if not type_.endswith(service_type_name(name, allow_underscores=True)):
             raise BadTypeInNameException
         self.type = type_
         self.name = name
         if addresses is not None:
             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
@@ -2005,41 +2016,42 @@
     return list(set(addr.ip for iface in ifaddr.get_adapters() for addr in 
iface.ips if addr.is_IPv4))
 
 
-def get_all_addresses_v6() -> List[int]:
+def get_all_addresses_v6() -> List[Tuple[Tuple[str, int, int], int]]:
     # IPv6 multicast uses positive indexes for interfaces
-    try:
-        nameindex = socket.if_nameindex
-    except AttributeError:
-        # Requires Python 3.8 on Windows. Fall back to Default.
-        QuietLogger.log_warning_once(
-            'if_nameindex is not available, falling back to using the default 
IPv6 interface'
-        )
-        return [0]
-
-    return [tpl[0] for tpl in nameindex()]
-
+    # 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)
+    )
 
-def ip_to_index(adapters: List[Any], ip: str) -> int:
-    if os.name != 'posix':
-        # Adapter names that ifaddr reports are not compatible with what 
if_nametoindex expects on Windows.
-        # We need https://github.com/pydron/ifaddr/pull/21 but it seems stuck 
on review.
-        raise RuntimeError('Converting from IP addresses to indexes is not 
supported on non-POSIX systems')
 
+def ip6_to_address_and_index(adapters: List[Any], ip: str) -> Tuple[Tuple[str, 
int, int], int]:
     ipaddr = ipaddress.ip_address(ip)
     for adapter in adapters:
         for adapter_ip in adapter.ips:
             # IPv6 addresses are represented as tuples
             if isinstance(adapter_ip.ip, tuple) and 
ipaddress.ip_address(adapter_ip.ip[0]) == ipaddr:
-                return socket.if_nametoindex(adapter.name)
+                return (cast(Tuple[str, int, int], adapter_ip.ip), cast(int, 
adapter.index))
 
     raise RuntimeError('No adapter found for IP address %s' % ip)
 
 
-def ip6_addresses_to_indexes(interfaces: List[Union[str, int]]) -> List[int]:
+def interface_index_to_ip6_address(adapters: List[Any], index: int) -> 
Tuple[str, int, int]:
+    for adapter in adapters:
+        if adapter.index == index:
+            for adapter_ip in adapter.ips:
+                # IPv6 addresses are represented as tuples
+                if isinstance(adapter_ip.ip, tuple):
+                    return cast(Tuple[str, int, int], adapter_ip.ip)
+
+    raise RuntimeError('No adapter found for index %s' % index)
+
+
+def ip6_addresses_to_indexes(
+    interfaces: List[Union[str, int, Tuple[Tuple[str, int, int], int]]]
+) -> List[Tuple[Tuple[str, int, int], int]]:
     """Convert IPv6 interface addresses to interface indexes.
 
-    IPv4 addresses are ignored. The conversion currently only works on POSIX
-    systems.
+    IPv4 addresses are ignored.
 
     :param interfaces: List of IP addresses and indexes.
     :returns: List of indexes.
@@ -2049,27 +2061,27 @@
 
     for iface in interfaces:
         if isinstance(iface, int):
-            result.append(iface)
+            result.append((interface_index_to_ip6_address(adapters, iface), 
iface))
         elif isinstance(iface, str) and ipaddress.ip_address(iface).version == 
6:
-            result.append(ip_to_index(adapters, iface))
+            result.append(ip6_to_address_and_index(adapters, iface))
 
     return result
 
 
 def normalize_interface_choice(
     choice: InterfacesType, ip_version: IPVersion = IPVersion.V4Only
-) -> List[Union[str, int]]:
+) -> List[Union[str, Tuple[Tuple[str, int, int], int]]]:
     """Convert the interfaces choice into internal representation.
 
     :param choice: `InterfaceChoice` or list of interface addresses or indexes 
(IPv6 only).
     :param ip_address: IP version to use (ignored if `choice` is a list).
     :returns: List of IP addresses (for IPv4) and indexes (for IPv6).
     """
-    result = []  # type: List[Union[str, int]]
+    result = []  # type: List[Union[str, Tuple[Tuple[str, int, int], int]]]
     if choice is InterfaceChoice.Default:
         if ip_version != IPVersion.V4Only:
             # IPv6 multicast uses interface 0 to mean the default
-            result.append(0)
+            result.append((('', 0, 0), 0))
         if ip_version != IPVersion.V6Only:
             result.append('0.0.0.0')
     elif choice is InterfaceChoice.All:
@@ -2092,8 +2104,18 @@
 
 
 def new_socket(
-    port: int = _MDNS_PORT, ip_version: IPVersion = IPVersion.V4Only, 
apple_p2p: bool = False
+    bind_addr: Union[Tuple[str], Tuple[str, int, int]],
+    port: int = _MDNS_PORT,
+    ip_version: IPVersion = IPVersion.V4Only,
+    apple_p2p: bool = False,
 ) -> socket.socket:
+    log.debug(
+        'Creating new socket with port %s, ip_version %s, apple_p2p %s and 
bind_addr %r',
+        port,
+        ip_version,
+        apple_p2p,
+        bind_addr,
+    )
     if ip_version == IPVersion.V4Only:
         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     else:
@@ -2145,19 +2167,25 @@
         # 
https://opensource.apple.com/source/xnu/xnu-4570.41.2/bsd/sys/socket.h
         s.setsockopt(socket.SOL_SOCKET, 0x1104, 1)
 
-    s.bind(('', port))
+    s.bind((bind_addr[0], port, *bind_addr[1:]))
+    log.debug('Created socket %s', s)
     return s
 
 
 def add_multicast_member(
-    listen_socket: socket.socket, interface: Union[str, int], apple_p2p: bool 
= False
+    listen_socket: socket.socket,
+    interface: Union[str, Tuple[Tuple[str, int, int], int]],
+    apple_p2p: bool = False,
 ) -> Optional[socket.socket]:
     # This is based on assumptions in normalize_interface_choice
-    is_v6 = isinstance(interface, int)
+    is_v6 = isinstance(interface, tuple)
+    err_einval = {errno.EINVAL}
+    if sys.platform == 'win32':
+        err_einval |= {errno.WSAEINVAL}
     log.debug('Adding %r (socket %d) to multicast group', interface, 
listen_socket.fileno())
     try:
         if is_v6:
-            iface_bin = struct.pack('@I', cast(int, interface))
+            iface_bin = struct.pack('@I', cast(int, interface[1]))
             _value = _MDNS_ADDR6_BYTES + iface_bin
             listen_socket.setsockopt(_IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, 
_value)
         else:
@@ -2179,16 +2207,18 @@
                 interface,
             )
             return None
-        elif _errno == errno.EINVAL:
+        elif _errno in err_einval:
             log.info('Interface of %s does not support multicast, ' 'it is 
expected in WSL', interface)
             return None
         else:
             raise
 
     respond_socket = new_socket(
-        ip_version=(IPVersion.V6Only if is_v6 else IPVersion.V4Only), 
apple_p2p=apple_p2p
+        ip_version=(IPVersion.V6Only if is_v6 else IPVersion.V4Only),
+        apple_p2p=apple_p2p,
+        bind_addr=cast(Tuple[Tuple[str, int, int], int], interface)[0] if 
is_v6 else (cast(str, interface),),
     )
-    log.debug('Configuring socket %d with multicast interface %s', 
respond_socket, interface)
+    log.debug('Configuring socket %s with multicast interface %s', 
respond_socket, interface)
     if is_v6:
         respond_socket.setsockopt(_IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, 
iface_bin)
     else:
@@ -2207,17 +2237,22 @@
     if unicast:
         listen_socket = None
     else:
-        listen_socket = new_socket(ip_version=ip_version, apple_p2p=apple_p2p)
+        listen_socket = new_socket(ip_version=ip_version, apple_p2p=apple_p2p, 
bind_addr=('',))
 
-    interfaces = normalize_interface_choice(interfaces, ip_version)
+    normalized_interfaces = normalize_interface_choice(interfaces, ip_version)
 
     respond_sockets = []
 
-    for i in interfaces:
+    for i in normalized_interfaces:
         if not unicast:
             respond_socket = add_multicast_member(cast(socket.socket, 
listen_socket), i, apple_p2p=apple_p2p)
         else:
-            respond_socket = new_socket(port=0, ip_version=ip_version, 
apple_p2p=apple_p2p)
+            respond_socket = new_socket(
+                port=0,
+                ip_version=ip_version,
+                apple_p2p=apple_p2p,
+                bind_addr=i[0] if isinstance(i, tuple) else (i,),
+            )
 
         if respond_socket is not None:
             respond_sockets.append(respond_socket)
@@ -2256,7 +2291,6 @@
             (IPv4 and IPv6) and interface indexes (IPv6 only).
 
             IPv6 notes for non-POSIX systems:
-            * IPv6 addresses are not supported, use indexes instead.
             * `InterfaceChoice.All` is an alias for `InterfaceChoice.Default`
               on Python versions before 3.8.
 
@@ -2289,6 +2323,7 @@
         self._listen_socket, self._respond_sockets = create_sockets(
             interfaces, unicast, ip_version, apple_p2p=apple_p2p
         )
+        log.debug('Listen socket %s, respond sockets %s', self._listen_socket, 
self._respond_sockets)
 
         self.listeners = []  # type: List[RecordUpdateListener]
         self.browsers = {}  # type: Dict[ServiceListener, ServiceBrowser]
@@ -2308,9 +2343,8 @@
         self.listener = Listener(self)
         if not unicast:
             self.engine.add_reader(self.listener, cast(socket.socket, 
self._listen_socket))
-        else:
-            for s in self._respond_sockets:
-                self.engine.add_reader(self.listener, s)
+        for s in self._respond_sockets:
+            self.engine.add_reader(self.listener, s)
         self.reaper = Reaper(self)
 
         self.debug = None  # type: Optional[DNSOutgoing]
@@ -2818,9 +2852,8 @@
             if not self.unicast:
                 self.engine.del_reader(cast(socket.socket, 
self._listen_socket))
                 cast(socket.socket, self._listen_socket).close()
-            else:
-                for s in self._respond_sockets:
-                    self.engine.del_reader(s)
+            for s in self._respond_sockets:
+                self.engine.del_reader(s)
             self.engine.join()
 
             # shutdown the rest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-zeroconf-0.27.1/zeroconf/test.py 
new/python-zeroconf-0.28.0/zeroconf/test.py
--- old/python-zeroconf-0.27.1/zeroconf/test.py 2020-06-05 11:09:58.000000000 
+0200
+++ new/python-zeroconf-0.28.0/zeroconf/test.py 2020-07-07 13:22:12.000000000 
+0200
@@ -1488,19 +1488,44 @@
 
     assert info.addresses == [address, address]
 
+    info = ServiceInfo(
+        type_,
+        registration_name,
+        80,
+        0,
+        0,
+        desc,
+        "ash-2.local.",
+        parsed_addresses=[address_parsed, address_parsed],
+    )
+    assert info.addresses == [address, address]
+
     if socket.has_ipv6 and not os.environ.get('SKIP_IPV6'):
         address_v6_parsed = "2001:db8::1"
         address_v6 = socket.inet_pton(socket.AF_INET6, address_v6_parsed)
-        info = ServiceInfo(
-            type_, registration_name, 80, 0, 0, desc, "ash-2.local.", 
addresses=[address, address_v6],
-        )
-        assert info.addresses == [address]
-        assert info.addresses_by_version(r.IPVersion.All) == [address, 
address_v6]
-        assert info.addresses_by_version(r.IPVersion.V4Only) == [address]
-        assert info.addresses_by_version(r.IPVersion.V6Only) == [address_v6]
-        assert info.parsed_addresses() == [address_parsed, address_v6_parsed]
-        assert info.parsed_addresses(r.IPVersion.V4Only) == [address_parsed]
-        assert info.parsed_addresses(r.IPVersion.V6Only) == [address_v6_parsed]
+        infos = [
+            ServiceInfo(
+                type_, registration_name, 80, 0, 0, desc, "ash-2.local.", 
addresses=[address, address_v6],
+            ),
+            ServiceInfo(
+                type_,
+                registration_name,
+                80,
+                0,
+                0,
+                desc,
+                "ash-2.local.",
+                parsed_addresses=[address_parsed, address_v6_parsed],
+            ),
+        ]
+        for info in infos:
+            assert info.addresses == [address]
+            assert info.addresses_by_version(r.IPVersion.All) == [address, 
address_v6]
+            assert info.addresses_by_version(r.IPVersion.V4Only) == [address]
+            assert info.addresses_by_version(r.IPVersion.V6Only) == 
[address_v6]
+            assert info.parsed_addresses() == [address_parsed, 
address_v6_parsed]
+            assert info.parsed_addresses(r.IPVersion.V4Only) == 
[address_parsed]
+            assert info.parsed_addresses(r.IPVersion.V6Only) == 
[address_v6_parsed]
 
 
 def test_ptr_optimization():


Reply via email to