Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/prop/binary.py: 59%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

66 statements  

1"""BINARY values from :rfc:`5545`.""" 

2 

3import base64 

4import binascii 

5from typing import ClassVar 

6 

7from icalendar.compatibility import Self, deprecate_for_version_8 

8from icalendar.error import JCalParsingError 

9from icalendar.parser import Parameters 

10from icalendar.parser_tools import to_unicode 

11 

12 

13class vBinary: 

14 """Binary property values are Base64 encoded.""" 

15 

16 default_value: ClassVar[str] = "BINARY" 

17 params: Parameters 

18 bytes: bytes 

19 """The raw binary value of the BINARY property. 

20 

21 This is the authoritative storage and round-trips losslessly, including 

22 for non-UTF-8 data. Use this instead of the deprecated :attr:`obj`. 

23 """ 

24 

25 def __init__(self, obj: str | bytes, params: dict[str, str] | None = None) -> None: 

26 if isinstance(obj, str): 

27 self.bytes = obj.encode("utf-8") 

28 else: 

29 self.bytes = obj 

30 self.params = Parameters(encoding="BASE64", value="BINARY") 

31 if params: 

32 self.params.update(params) 

33 

34 def __repr__(self) -> str: 

35 return f"vBinary({self.to_ical()})" 

36 

37 def to_ical(self) -> bytes: 

38 return base64.b64encode(self.bytes) 

39 

40 @staticmethod 

41 def from_ical(ical: str | bytes) -> bytes: 

42 try: 

43 return base64.b64decode(ical, validate=True) 

44 except (binascii.Error, ValueError) as e: 

45 raise ValueError("Not valid base 64 encoding.") from e 

46 

47 @property 

48 def base64data(self) -> str: 

49 """The Base64-encoded string view of this value. 

50 

51 This is the same string that :meth:`to_ical` produces, exposed as 

52 a plain :class:`str` instead of :class:`bytes` so you don't need to 

53 call :func:`base64.b64encode` yourself. See :issue:`1550`. 

54 

55 Returns: 

56 The Base64-encoded representation of the stored value. 

57 """ 

58 return self.to_ical().decode("ascii") 

59 

60 @base64data.setter 

61 def base64data(self, value: str) -> None: 

62 """Set this value from a Base64-encoded string. 

63 

64 The decoded raw bytes are stored in :attr:`bytes`, so non-UTF-8 

65 payloads round-trip losslessly. 

66 

67 Parameters: 

68 value: A Base64-encoded string. 

69 

70 Raises: 

71 ValueError: If ``value`` isn't valid Base64. 

72 """ 

73 self.bytes = self.from_ical(value) 

74 

75 @property 

76 @deprecate_for_version_8 

77 def obj(self) -> str: 

78 """Deprecated string view of the value. 

79 

80 .. deprecated:: 7.1.3 

81 Use :attr:`bytes` for the raw binary value. ``obj`` decodes 

82 :attr:`bytes` as text and is lossy for non-UTF-8 data. It will 

83 be removed in icalendar 8. 

84 """ 

85 return to_unicode(self.bytes) 

86 

87 @obj.setter 

88 @deprecate_for_version_8 

89 def obj(self, value: str | bytes) -> None: 

90 self.bytes = value.encode("utf-8") if isinstance(value, str) else value 

91 

92 def __eq__(self, other: object) -> bool: 

93 """self == other""" 

94 return isinstance(other, vBinary) and self.bytes == other.bytes 

95 

96 def __hash__(self) -> int: 

97 """Hash of the vBinary object.""" 

98 return hash(self.bytes) 

99 

100 @classmethod 

101 def examples(cls) -> list[Self]: 

102 """Examples of vBinary.""" 

103 return [cls("VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4")] 

104 

105 from icalendar.param import VALUE 

106 

107 def to_jcal(self, name: str) -> list: 

108 """The jCal representation of this property according to :rfc:`7265`.""" 

109 params = self.params.to_jcal() 

110 if params.get("encoding") == "BASE64": 

111 # BASE64 is the only allowed encoding 

112 del params["encoding"] 

113 return [name, params, self.VALUE.lower(), self.base64data] 

114 

115 @property 

116 def ical_value(self) -> bytes: 

117 """The raw ``bytes`` value of the BINARY property. 

118 

119 .. versionadded:: 7.1.0 

120 

121 .. versionchanged:: 7.1.3 

122 Returns the raw stored bytes. Previously the stored value was 

123 Base64-decoded, which raised :class:`ValueError` for non-Base64 

124 input. See :pr:`1356`. 

125 """ 

126 return self.bytes 

127 

128 @classmethod 

129 def from_jcal(cls, jcal_property: list) -> Self: 

130 """Parse jCal from :rfc:`7265` to a vBinary. 

131 

132 Parameters: 

133 jcal_property: The jCal property to parse. 

134 

135 Raises: 

136 ~error.JCalParsingError: If the provided jCal is invalid. 

137 """ 

138 JCalParsingError.validate_property(jcal_property, cls) 

139 JCalParsingError.validate_value_type(jcal_property[3], str, cls, 3) 

140 return cls( 

141 cls.from_ical(jcal_property[3]), 

142 params=Parameters.from_jcal_property(jcal_property), 

143 ) 

144 

145 

146__all__ = ["vBinary"]