Coverage for aiocoap / util / linkformat.py: 100%

19 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-17 12:28 +0000

1# SPDX-FileCopyrightText: Christian Amsüss and the aiocoap contributors 

2# 

3# SPDX-License-Identifier: MIT 

4 

5"""This module contains in-place modifications to the LinkHeader module to 

6satisfy RFC6690 constraints. 

7 

8It is a general nursery for what aiocoap needs of link-format management before 

9any of this is split out into its own package. 

10""" 

11 

12from .vendored import link_header 

13 

14 

15class LinkFormat(link_header.LinkHeader): 

16 """Variation of the now vendered-in link_header package. 

17 

18 This accounts for the RFC6690 constraint (not present in RFC5899) that 

19 there be no space after commas or semicolons. 

20 

21 >>> str(LinkFormat([Link("/parent/", rel="up"), Link("/parent/here/child")])) 

22 '</parent/>;rel="up",</parent/here/child>' 

23 """ 

24 

25 def __str__(self): 

26 return ",".join(str(link) for link in self.links) 

27 

28 

29class Link(link_header.Link): 

30 # This is copy-pasted from the link_header module's code, just replacing 

31 # the '; ' with ';'. 

32 # 

33 # Original copyright Michael Burrows <mjb@asplake.co.uk>, distributed under 

34 # the BSD license 

35 def __str__(self): 

36 def str_pair(key, value): 

37 if value is None: 

38 return key 

39 # workaround to accommodate copper 

40 # elif RE_ONLY_TOKEN.match(value) or key.endswith('*'): 

41 # return '%s=%s' % (key, value) 

42 else: 

43 return '%s="%s"' % (key, value.replace('"', r"\"")) 

44 

45 return ";".join( 

46 ["<%s>" % self.href] 

47 + [str_pair(key, value) for key, value in self.attr_pairs] 

48 ) 

49 

50 

51def parse(linkformat: str | bytes) -> LinkFormat: 

52 """Parses RFC6690 links. 

53 

54 Unlike the (now vendored-in) link_header package's parsing, this 

55 

56 - accepts either bytes or strings; the former are decoded as UTF-8 

57 - produces types that, in their serialization, account for differences between RFC6690 and RFC5899 

58 

59 >>> parse(b"</hell\\xc3\\xb6>") 

60 LinkHeader([Link('/hellö')]) 

61 >>> parse("</hellö>") 

62 LinkHeader([Link('/hellö')]) 

63 """ 

64 if isinstance(linkformat, bytes): 

65 linkformat = linkformat.decode("utf-8") 

66 data = link_header.parse(linkformat) 

67 data.__class__ = LinkFormat 

68 for link in data.links: 

69 link.__class__ = Link 

70 return data