Skip to content

Commit 9b595a1

Browse files
authored
feat: add decoded_properties method to ServiceInfo (#1332)
1 parent d29553a commit 9b595a1

3 files changed

Lines changed: 32 additions & 0 deletions

File tree

src/zeroconf/_services/info.pxd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ cdef class ServiceInfo(RecordUpdateListener):
5353
cdef public str server
5454
cdef public str server_key
5555
cdef public cython.dict _properties
56+
cdef public cython.dict _decoded_properties
5657
cdef public object host_ttl
5758
cdef public object other_ttl
5859
cdef public object interface_index
@@ -72,6 +73,9 @@ cdef class ServiceInfo(RecordUpdateListener):
7273
@cython.locals(length="unsigned char", index="unsigned int", key_value=bytes, key_sep_value=tuple)
7374
cdef void _unpack_text_into_properties(self)
7475

76+
@cython.locals(k=bytes, v=bytes)
77+
cdef void _generate_decoded_properties(self)
78+
7579
@cython.locals(properties_contain_str=bint)
7680
cpdef _set_properties(self, cython.dict properties)
7781

src/zeroconf/_services/info.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class ServiceInfo(RecordUpdateListener):
143143
"server",
144144
"server_key",
145145
"_properties",
146+
"_decoded_properties",
146147
"host_ttl",
147148
"other_ttl",
148149
"interface_index",
@@ -192,6 +193,7 @@ def __init__(
192193
self.server = server if server else None
193194
self.server_key = server.lower() if server else None
194195
self._properties: Optional[Dict[bytes, Optional[bytes]]] = None
196+
self._decoded_properties: Optional[Dict[str, Optional[str]]] = None
195197
if isinstance(properties, bytes):
196198
self._set_text(properties)
197199
else:
@@ -268,6 +270,15 @@ def properties(self) -> Dict[bytes, Optional[bytes]]:
268270
assert self._properties is not None
269271
return self._properties
270272

273+
@property
274+
def decoded_properties(self) -> Dict[str, Optional[str]]:
275+
"""Return properties as strings."""
276+
if self._decoded_properties is None:
277+
self._generate_decoded_properties()
278+
if TYPE_CHECKING:
279+
assert self._decoded_properties is not None
280+
return self._decoded_properties
281+
271282
def async_clear_cache(self) -> None:
272283
"""Clear the cache for this service info."""
273284
self._dns_address_cache = None
@@ -384,6 +395,14 @@ def _set_text(self, text: bytes) -> None:
384395
self.text = text
385396
# Clear the properties cache
386397
self._properties = None
398+
self._decoded_properties = None
399+
400+
def _generate_decoded_properties(self) -> None:
401+
"""Generates decoded properties from the properties"""
402+
self._decoded_properties = {
403+
k.decode("ascii", "replace"): None if v is None else v.decode("utf-8", "replace")
404+
for k, v in self.properties.items()
405+
}
387406

388407
def _unpack_text_into_properties(self) -> None:
389408
"""Unpacks the text field into properties"""

tests/test_services.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ def update_service(self, zeroconf, type, name):
134134
assert info.properties[b'prop_true'] == b'1'
135135
assert info.properties[b'prop_false'] == b'0'
136136

137+
assert info.decoded_properties['prop_none'] is None
138+
assert info.decoded_properties['prop_string'] == b'a_prop'.decode('utf-8')
139+
assert info.decoded_properties['prop_float'] == '1.0'
140+
assert info.decoded_properties['prop_blank'] == b'a blanked string'.decode('utf-8')
141+
assert info.decoded_properties['prop_true'] == '1'
142+
assert info.decoded_properties['prop_false'] == '0'
143+
137144
assert info.addresses == addresses[:1] # no V6 by default
138145
assert set(info.addresses_by_version(r.IPVersion.All)) == set(addresses)
139146

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

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

203212
zeroconf_registrar.unregister_service(info_service)
204213
service_removed.wait(1)

0 commit comments

Comments
 (0)