From 9d7b47b4c90edf68c28aa1a3b8ef6e9d404201d4 Mon Sep 17 00:00:00 2001 From: Rotzbua Date: Mon, 10 Feb 2025 17:23:57 +0100 Subject: [PATCH] chore: add typing, enable additional mypy checks --- .pre-commit-config.yaml | 2 +- pyproject.toml | 10 ++++++++-- src/zeroconf/_dns.py | 18 +++++++++--------- src/zeroconf/_listener.py | 4 ++-- src/zeroconf/_utils/net.py | 8 ++++---- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8ea453bc..afeeffbf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -57,7 +57,7 @@ repos: rev: v1.15.0 hooks: - id: mypy - additional_dependencies: [] + additional_dependencies: [ifaddr] - repo: https://github.com/MarcoGorelli/cython-lint rev: v0.16.6 hooks: diff --git a/pyproject.toml b/pyproject.toml index 0bb177ba..3bcd954a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -162,15 +162,21 @@ profile = "black" known_first_party = ["zeroconf", "tests"] [tool.mypy] +warn_unused_configs = true check_untyped_defs = true disallow_any_generics = false # turn this on when we drop 3.7/3.8 support disallow_incomplete_defs = true disallow_untyped_defs = true +warn_incomplete_stub = true mypy_path = "src/" -no_implicit_optional = true show_error_codes = true +warn_redundant_casts = false # Activate for cleanup. +warn_return_any = true warn_unreachable = true -warn_unused_ignores = false +warn_unused_ignores = false # Does not always work properly, activate for cleanup. +extra_checks = true +strict_equality = true +strict_bytes = true # Will be true by default with mypy v2 release. exclude = [ 'docs/*', 'bench/*', diff --git a/src/zeroconf/_dns.py b/src/zeroconf/_dns.py index bc0a3948..591eb018 100644 --- a/src/zeroconf/_dns.py +++ b/src/zeroconf/_dns.py @@ -79,7 +79,7 @@ def _fast_init_entry(self, name: str, type_: _int, class_: _int) -> None: self.class_ = class_ & _CLASS_MASK self.unique = (class_ & _CLASS_UNIQUE) != 0 - def _dns_entry_matches(self, other) -> bool: # type: ignore[no-untyped-def] + def _dns_entry_matches(self, other: DNSEntry) -> bool: return self.key == other.key and self.type == other.type and self.class_ == other.class_ def __eq__(self, other: Any) -> bool: @@ -135,7 +135,7 @@ def __eq__(self, other: Any) -> bool: @property def max_size(self) -> int: """Maximum size of the question in the packet.""" - return len(self.name.encode("utf-8")) + _LEN_BYTE + _LEN_SHORT + _LEN_SHORT # type # class + return len(self.name.encode("utf-8")) + _LEN_BYTE + _LEN_SHORT + _LEN_SHORT @property def unicast(self) -> bool: @@ -199,7 +199,7 @@ def suppressed_by(self, msg: DNSIncoming) -> bool: return True return False - def _suppressed_by_answer(self, other) -> bool: # type: ignore[no-untyped-def] + def _suppressed_by_answer(self, other: DNSRecord) -> bool: """Returns true if another record has same name, type and class, and if its TTL is at least half of this record's.""" return self == other and other.ttl > (self.ttl / 2) @@ -285,7 +285,7 @@ def __eq__(self, other: Any) -> bool: """Tests equality on address""" return isinstance(other, DNSAddress) and self._eq(other) - def _eq(self, other) -> bool: # type: ignore[no-untyped-def] + def _eq(self, other: DNSAddress) -> bool: return ( self.address == other.address and self.scope_id == other.scope_id @@ -344,7 +344,7 @@ def __eq__(self, other: Any) -> bool: """Tests equality on cpu and os.""" return isinstance(other, DNSHinfo) and self._eq(other) - def _eq(self, other) -> bool: # type: ignore[no-untyped-def] + def _eq(self, other: DNSHinfo) -> bool: """Tests equality on cpu and os.""" return self.cpu == other.cpu and self.os == other.os and self._dns_entry_matches(other) @@ -399,7 +399,7 @@ def __eq__(self, other: Any) -> bool: """Tests equality on alias.""" return isinstance(other, DNSPointer) and self._eq(other) - def _eq(self, other) -> bool: # type: ignore[no-untyped-def] + def _eq(self, other: DNSPointer) -> bool: """Tests equality on alias.""" return self.alias_key == other.alias_key and self._dns_entry_matches(other) @@ -447,7 +447,7 @@ def __eq__(self, other: Any) -> bool: """Tests equality on text.""" return isinstance(other, DNSText) and self._eq(other) - def _eq(self, other) -> bool: # type: ignore[no-untyped-def] + def _eq(self, other: DNSText) -> bool: """Tests equality on text.""" return self.text == other.text and self._dns_entry_matches(other) @@ -510,7 +510,7 @@ def __eq__(self, other: Any) -> bool: """Tests equality on priority, weight, port and server""" return isinstance(other, DNSService) and self._eq(other) - def _eq(self, other) -> bool: # type: ignore[no-untyped-def] + def _eq(self, other: DNSService) -> bool: """Tests equality on priority, weight, port and server.""" return ( self.priority == other.priority @@ -585,7 +585,7 @@ def __eq__(self, other: Any) -> bool: """Tests equality on next_name and rdtypes.""" return isinstance(other, DNSNsec) and self._eq(other) - def _eq(self, other) -> bool: # type: ignore[no-untyped-def] + def _eq(self, other: DNSNsec) -> bool: """Tests equality on next_name and rdtypes.""" return ( self.next_name == other.next_name diff --git a/src/zeroconf/_listener.py b/src/zeroconf/_listener.py index 406273e9..ed503169 100644 --- a/src/zeroconf/_listener.py +++ b/src/zeroconf/_listener.py @@ -131,14 +131,14 @@ def _process_datagram_at_time( if len(addrs) == 2: v6_flow_scope: tuple[()] | tuple[int, int] = () # https://github.com/python/mypy/issues/1178 - addr, port = addrs # type: ignore + addr, port = addrs addr_port = addrs if TYPE_CHECKING: addr_port = cast(tuple[str, int], addr_port) scope = None else: # https://github.com/python/mypy/issues/1178 - addr, port, flow, scope = addrs # type: ignore + addr, port, flow, scope = addrs if debug: # pragma: no branch log.debug("IPv6 scope_id %d associated to the receiving interface", scope) v6_flow_scope = (flow, scope) diff --git a/src/zeroconf/_utils/net.py b/src/zeroconf/_utils/net.py index 3321211f..62033ad5 100644 --- a/src/zeroconf/_utils/net.py +++ b/src/zeroconf/_utils/net.py @@ -74,14 +74,14 @@ def _encode_address(address: str) -> bytes: def get_all_addresses() -> list[str]: - return list({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}) # type: ignore[misc] 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( - {(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} # type: ignore[misc] ) @@ -127,9 +127,9 @@ def ip6_addresses_to_indexes( for iface in interfaces: if isinstance(iface, int): - result.append((interface_index_to_ip6_address(adapters, iface), iface)) + result.append((interface_index_to_ip6_address(adapters, iface), iface)) # type: ignore[arg-type] elif isinstance(iface, str) and ipaddress.ip_address(iface).version == 6: - result.append(ip6_to_address_and_index(adapters, iface)) + result.append(ip6_to_address_and_index(adapters, iface)) # type: ignore[arg-type] return result