feat: optimize equality checks for DNS records (#1120) · python-zeroconf/python-zeroconf@3a25ff7
@@ -72,9 +72,12 @@ def __init__(self, name: str, type_: int, class_: int) -> None:
7272self.class_ = class_ & _CLASS_MASK
7373self.unique = (class_ & _CLASS_UNIQUE) != 0
747475+def _dns_entry_matches(self, other) -> bool: # type: ignore[no-untyped-def]
76+return self.key == other.key and self.type == other.type and self.class_ == other.class_
77+7578def __eq__(self, other: Any) -> bool:
7679"""Equality test on key (lowercase name), type, and class"""
77-return _dns_entry_matches(other, self.key, self.type, self.class_) and isinstance(other, DNSEntry)
80+return isinstance(other, DNSEntry) and self._dns_entry_matches(other)
78817982@staticmethod
8083def get_class_(class_: int) -> str:
@@ -117,7 +120,7 @@ def __hash__(self) -> int:
117120118121def __eq__(self, other: Any) -> bool:
119122"""Tests equality on dns question."""
120-return isinstance(other, DNSQuestion) and _dns_entry_matches(other, self.key, self.type, self.class_)
123+return isinstance(other, DNSQuestion) and self._dns_entry_matches(other)
121124122125@property
123126def max_size(self) -> int:
@@ -169,9 +172,9 @@ def __eq__(self, other: Any) -> bool: # pylint: disable=no-self-use
169172def suppressed_by(self, msg: 'DNSIncoming') -> bool:
170173"""Returns true if any answer in a message can suffice for the
171174 information held in this record."""
172-return any(self.suppressed_by_answer(record) for record in msg.answers)
175+return any(self._suppressed_by_answer(record) for record in msg.answers)
173176174-def suppressed_by_answer(self, other: 'DNSRecord') -> bool:
177+def _suppressed_by_answer(self, other) -> bool: # type: ignore[no-untyped-def]
175178"""Returns true if another record has same name, type and class,
176179 and if its TTL is at least half of this record's."""
177180return self == other and other.ttl > (self.ttl / 2)
@@ -246,11 +249,13 @@ def write(self, out: 'DNSOutgoing') -> None:
246249247250def __eq__(self, other: Any) -> bool:
248251"""Tests equality on address"""
252+return isinstance(other, DNSAddress) and self._eq(other)
253+254+def _eq(self, other) -> bool: # type: ignore[no-untyped-def]
249255return (
250-isinstance(other, DNSAddress)
251-and self.address == other.address
256+self.address == other.address
252257and self.scope_id == other.scope_id
253-and _dns_entry_matches(other, self.key, self.type, self.class_)
258+and self._dns_entry_matches(other)
254259 )
255260256261def __hash__(self) -> int:
@@ -289,13 +294,12 @@ def write(self, out: 'DNSOutgoing') -> None:
289294out.write_character_string(self.os.encode('utf-8'))
290295291296def __eq__(self, other: Any) -> bool:
292-"""Tests equality on cpu and os"""
293-return (
294-isinstance(other, DNSHinfo)
295-and self.cpu == other.cpu
296-and self.os == other.os
297-and _dns_entry_matches(other, self.key, self.type, self.class_)
298- )
297+"""Tests equality on cpu and os."""
298+return isinstance(other, DNSHinfo) and self._eq(other)
299+300+def _eq(self, other) -> bool: # type: ignore[no-untyped-def]
301+"""Tests equality on cpu and os."""
302+return self.cpu == other.cpu and self.os == other.os and self._dns_entry_matches(other)
299303300304def __hash__(self) -> int:
301305"""Hash to compare like DNSHinfo."""
@@ -334,12 +338,12 @@ def write(self, out: 'DNSOutgoing') -> None:
334338out.write_name(self.alias)
335339336340def __eq__(self, other: Any) -> bool:
337-"""Tests equality on alias"""
338-return (
339- isinstance(other, DNSPointer)
340- and self.alias == other.alias
341- and _dns_entry_matches(other, self.key, self.type, self.class_)
342- )
341+"""Tests equality on alias."""
342+return isinstance(other, DNSPointer) and self._eq(other)
343+344+def _eq(self, other) -> bool: # type: ignore[no-untyped-def]
345+"""Tests equality on alias."""
346+return self.alias == other.alias and self._dns_entry_matches(other)
343347344348def __hash__(self) -> int:
345349"""Hash to compare like DNSPointer."""
@@ -373,12 +377,12 @@ def __hash__(self) -> int:
373377return self._hash
374378375379def __eq__(self, other: Any) -> bool:
376-"""Tests equality on text"""
377-return (
378- isinstance(other, DNSText)
379- and self.text == other.text
380- and _dns_entry_matches(other, self.key, self.type, self.class_)
381- )
380+"""Tests equality on text."""
381+return isinstance(other, DNSText) and self._eq(other)
382+383+def _eq(self, other) -> bool: # type: ignore[no-untyped-def]
384+"""Tests equality on text."""
385+return self.text == other.text and self._dns_entry_matches(other)
382386383387def __repr__(self) -> str:
384388"""String representation"""
@@ -422,13 +426,16 @@ def write(self, out: 'DNSOutgoing') -> None:
422426423427def __eq__(self, other: Any) -> bool:
424428"""Tests equality on priority, weight, port and server"""
429+return isinstance(other, DNSService) and self._eq(other)
430+431+def _eq(self, other) -> bool: # type: ignore[no-untyped-def]
432+"""Tests equality on priority, weight, port and server."""
425433return (
426-isinstance(other, DNSService)
427-and self.priority == other.priority
434+self.priority == other.priority
428435and self.weight == other.weight
429436and self.port == other.port
430437and self.server == other.server
431-and _dns_entry_matches(other, self.key, self.type, self.class_)
438+and self._dns_entry_matches(other)
432439 )
433440434441def __hash__(self) -> int:
@@ -478,12 +485,15 @@ def write(self, out: 'DNSOutgoing') -> None:
478485out.write_string(out_bytes)
479486480487def __eq__(self, other: Any) -> bool:
481-"""Tests equality on cpu and os"""
488+"""Tests equality on next_name and rdtypes."""
489+return isinstance(other, DNSNsec) and self._eq(other)
490+491+def _eq(self, other) -> bool: # type: ignore[no-untyped-def]
492+"""Tests equality on next_name and rdtypes."""
482493return (
483-isinstance(other, DNSNsec)
484-and self.next_name == other.next_name
494+self.next_name == other.next_name
485495and self.rdtypes == other.rdtypes
486-and _dns_entry_matches(other, self.key, self.type, self.class_)
496+and self._dns_entry_matches(other)
487497 )
488498489499def __hash__(self) -> int:
@@ -497,6 +507,9 @@ def __repr__(self) -> str:
497507 )
498508499509510+_DNSRecord = DNSRecord
511+512+500513class DNSRRSet:
501514"""A set of dns records independent of the ttl."""
502515@@ -514,20 +527,15 @@ def lookup(self) -> Dict[DNSRecord, DNSRecord]:
514527self._lookup = {record: record for record in self._records}
515528return self._lookup
516529517-def suppresses(self, record: DNSRecord) -> bool:
530+def suppresses(self, record: _DNSRecord) -> bool:
518531"""Returns true if any answer in the rrset can suffice for the
519532 information held in this record."""
520-other = self.lookup.get(record)
533+if self._lookup is None:
534+other = self.lookup.get(record)
535+else:
536+other = self._lookup.get(record)
521537return bool(other and other.ttl > (record.ttl / 2))
522538523539def __contains__(self, record: DNSRecord) -> bool:
524540"""Returns true if the rrset contains the record."""
525541return record in self.lookup
526-527-528-_DNSEntry = DNSEntry
529-_str = str
530-531-532-def _dns_entry_matches(entry: _DNSEntry, key: _str, type_: int, class_: int) -> bool:
533-return key == entry.key and type_ == entry.type and class_ == entry.class_