@@ -191,7 +191,7 @@ def __init__(
191191 self .priority = priority
192192 self .server = server if server else None
193193 self .server_key = server .lower () if server else None
194- self ._properties : Optional [Dict [Union [ str , bytes ] , Optional [Union [ str , bytes ] ]]] = None
194+ self ._properties : Optional [Dict [bytes , Optional [bytes ]]] = None
195195 if isinstance (properties , bytes ):
196196 self ._set_text (properties )
197197 else :
@@ -260,14 +260,8 @@ def addresses(self, value: List[bytes]) -> None:
260260 self ._ipv6_addresses .append (addr )
261261
262262 @property
263- def properties (self ) -> Dict [Union [str , bytes ], Optional [Union [str , bytes ]]]:
264- """If properties were set in the constructor this property returns the original dictionary
265- of type `Dict[Union[bytes, str], Any]`.
266-
267- If properties are coming from the network, after decoding a TXT record, the keys are always
268- bytes and the values are either bytes, if there was a value, even empty, or `None`, if there
269- was none. No further decoding is attempted. The type returned is `Dict[bytes, Optional[bytes]]`.
270- """
263+ def properties (self ) -> Dict [bytes , Optional [bytes ]]:
264+ """Return properties as bytes."""
271265 if self ._properties is None :
272266 self ._unpack_text_into_properties ()
273267 if TYPE_CHECKING :
@@ -356,21 +350,31 @@ def parsed_scoped_addresses(self, version: IPVersion = IPVersion.All) -> List[st
356350
357351 def _set_properties (self , properties : Dict [Union [str , bytes ], Optional [Union [str , bytes ]]]) -> None :
358352 """Sets properties and text of this info from a dictionary"""
359- self ._properties = properties
360353 list_ : List [bytes ] = []
354+ properties_contain_str = False
361355 result = b''
362356 for key , value in properties .items ():
363357 if isinstance (key , str ):
364358 key = key .encode ('utf-8' )
359+ properties_contain_str = True
365360
366361 record = key
367362 if value is not None :
368363 if not isinstance (value , bytes ):
369364 value = str (value ).encode ('utf-8' )
365+ properties_contain_str = True
370366 record += b'=' + value
371367 list_ .append (record )
372368 for item in list_ :
373369 result = b'' .join ((result , bytes ((len (item ),)), item ))
370+ if not properties_contain_str :
371+ # If there are no str keys or values, we can use the properties
372+ # as-is, without decoding them, otherwise calling
373+ # self.properties will lazy decode them, which is expensive.
374+ if TYPE_CHECKING :
375+ self ._properties = cast ("Dict[bytes, Optional[bytes]]" , properties )
376+ else :
377+ self ._properties = properties
374378 self .text = result
375379
376380 def _set_text (self , text : bytes ) -> None :
@@ -392,7 +396,7 @@ def _unpack_text_into_properties(self) -> None:
392396 return
393397
394398 index = 0
395- properties : Dict [Union [ str , bytes ] , Optional [Union [ str , bytes ] ]] = {}
399+ properties : Dict [bytes , Optional [bytes ]] = {}
396400 while index < end :
397401 length = text [index ]
398402 index += 1
0 commit comments