Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/zeroconf/_services/info.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ cdef class ServiceInfo(RecordUpdateListener):
cdef public str server
cdef public str server_key
cdef public cython.dict _properties
cdef public cython.dict _decoded_properties
cdef public object host_ttl
cdef public object other_ttl
cdef public object interface_index
Expand All @@ -72,6 +73,9 @@ cdef class ServiceInfo(RecordUpdateListener):
@cython.locals(length="unsigned char", index="unsigned int", key_value=bytes, key_sep_value=tuple)
cdef void _unpack_text_into_properties(self)

@cython.locals(k=bytes, v=bytes)
cdef void _generate_decoded_properties(self)

@cython.locals(properties_contain_str=bint)
cpdef _set_properties(self, cython.dict properties)

Expand Down
19 changes: 19 additions & 0 deletions src/zeroconf/_services/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class ServiceInfo(RecordUpdateListener):
"server",
"server_key",
"_properties",
"_decoded_properties",
"host_ttl",
"other_ttl",
"interface_index",
Expand Down Expand Up @@ -192,6 +193,7 @@ def __init__(
self.server = server if server else None
self.server_key = server.lower() if server else None
self._properties: Optional[Dict[bytes, Optional[bytes]]] = None
Comment thread
bdraco marked this conversation as resolved.
self._decoded_properties: Optional[Dict[str, Optional[str]]] = None
if isinstance(properties, bytes):
self._set_text(properties)
else:
Expand Down Expand Up @@ -268,6 +270,15 @@ def properties(self) -> Dict[bytes, Optional[bytes]]:
assert self._properties is not None
return self._properties

@property
def decoded_properties(self) -> Dict[str, Optional[str]]:
"""Return properties as strings."""
if self._decoded_properties is None:
self._generate_decoded_properties()
if TYPE_CHECKING:
assert self._decoded_properties is not None
return self._decoded_properties

def async_clear_cache(self) -> None:
"""Clear the cache for this service info."""
self._dns_address_cache = None
Expand Down Expand Up @@ -384,6 +395,14 @@ def _set_text(self, text: bytes) -> None:
self.text = text
# Clear the properties cache
self._properties = None
self._decoded_properties = None

def _generate_decoded_properties(self) -> None:
"""Generates decoded properties from the properties"""
self._decoded_properties = {
k.decode("ascii", "replace"): None if v is None else v.decode("utf-8", "replace")
for k, v in self.properties.items()
}

def _unpack_text_into_properties(self) -> None:
"""Unpacks the text field into properties"""
Expand Down
9 changes: 9 additions & 0 deletions tests/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ def update_service(self, zeroconf, type, name):
assert info.properties[b'prop_true'] == b'1'
assert info.properties[b'prop_false'] == b'0'

assert info.decoded_properties['prop_none'] is None
assert info.decoded_properties['prop_string'] == b'a_prop'.decode('utf-8')
assert info.decoded_properties['prop_float'] == '1.0'
assert info.decoded_properties['prop_blank'] == b'a blanked string'.decode('utf-8')
assert info.decoded_properties['prop_true'] == '1'
assert info.decoded_properties['prop_false'] == '0'

assert info.addresses == addresses[:1] # no V6 by default
assert set(info.addresses_by_version(r.IPVersion.All)) == set(addresses)

Expand Down Expand Up @@ -194,11 +201,13 @@ def update_service(self, zeroconf, type, name):
info = zeroconf_browser.get_service_info(type_, registration_name)
assert info is not None
assert info.properties[b'prop_blank'] == properties['prop_blank']
assert info.decoded_properties['prop_blank'] == b'an updated string'.decode('utf-8')

cached_info = ServiceInfo(subtype, registration_name)
cached_info.load_from_cache(zeroconf_browser)
assert cached_info.properties is not None
assert cached_info.properties[b'prop_blank'] == properties['prop_blank']
assert cached_info.decoded_properties['prop_blank'] == b'an updated string'.decode('utf-8')

zeroconf_registrar.unregister_service(info_service)
service_removed.wait(1)
Expand Down