Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/prop/dt/list.py: 66%

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

88 statements  

1from collections.abc import Sequence 

2from datetime import date, datetime 

3from typing import Any, ClassVar 

4from xml.etree.ElementTree import Element 

5 

6from icalendar.compatibility import Self 

7from icalendar.error import JCalParsingError, XCalParsingError 

8from icalendar.parser import Parameters 

9from icalendar.parser.xcal.base import XCalParser 

10from icalendar.parser.xcal.wrapper import from_xcal_wrapper 

11from icalendar.parser_tools import from_unicode 

12 

13from .base import TimeBase 

14from .types import vDDDTypes 

15 

16 

17class vDDDLists: 

18 """A list of vDDDTypes values.""" 

19 

20 default_value: ClassVar[str] = "DATE-TIME" 

21 params: Parameters 

22 dts: list[vDDDTypes] 

23 

24 def __init__(self, dt_list, params: dict[str, Any] | None = None) -> None: 

25 if params is None: 

26 params = {} 

27 if not hasattr(dt_list, "__iter__") or ( 

28 isinstance(dt_list, Sequence) and len(dt_list) == 2 and dt_list[1] is None 

29 ): 

30 # A ``(dt, None)`` pair (tuple or list) is the rdates form of a single 

31 # date, not a list of two values, so don't iterate it element-wise (#1439). 

32 dt_list = [dt_list] 

33 vddd = [] 

34 tzid = None 

35 for dt_l in dt_list: 

36 dt = vDDDTypes(dt_l) if not isinstance(dt_l, vDDDTypes) else dt_l 

37 vddd.append(dt) 

38 if "TZID" in dt.params: 

39 tzid = dt.params["TZID"] 

40 

41 if tzid: 

42 # NOTE: no support for multiple timezones here! 

43 params["TZID"] = tzid 

44 self.params = Parameters(params) 

45 self.dts = vddd 

46 

47 def to_ical(self): 

48 dts_ical = (from_unicode(dt.to_ical()) for dt in self.dts) 

49 return b",".join(dts_ical) 

50 

51 @staticmethod 

52 def from_ical(ical, timezone=None): 

53 out = [] 

54 ical_dates = ical.split(",") 

55 for ical_dt in ical_dates: 

56 out.append(vDDDTypes.from_ical(ical_dt, timezone=timezone)) 

57 return out 

58 

59 def __eq__(self, other): 

60 if isinstance(other, vDDDLists): 

61 return self.dts == other.dts 

62 if isinstance(other, (TimeBase, date)): 

63 return self.dts == [other] 

64 return False 

65 

66 def __repr__(self): 

67 """String representation.""" 

68 return f"{self.__class__.__name__}({self.dts})" 

69 

70 @classmethod 

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

72 """Examples of vDDDLists.""" 

73 return [cls([datetime(2025, 11, 10, 16, 50)])] 

74 

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

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

77 return [ 

78 name, 

79 self.params.to_jcal(), 

80 self.VALUE.lower(), 

81 *[dt.to_jcal(name)[3] for dt in self.dts], 

82 ] 

83 

84 def _get_value(self) -> str | None: 

85 return None if not self.dts else self.dts[0].VALUE 

86 

87 from icalendar.param import VALUE 

88 

89 @classmethod 

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

91 """Parse jCal from :rfc:`7265`. 

92 

93 Parameters: 

94 jcal_property: The jCal property to parse. 

95 

96 Raises: 

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

98 """ 

99 JCalParsingError.validate_property(jcal_property, cls) 

100 values = jcal_property[3:] 

101 prop = jcal_property[:3] 

102 dts = [] 

103 for value in values: 

104 dts.append(vDDDTypes.from_jcal(prop + [value])) 

105 return cls( 

106 dts, 

107 params=Parameters.from_jcal_property(jcal_property), 

108 ) 

109 

110 __hash__ = None 

111 

112 @property 

113 def dt(self) -> TimeBase: 

114 """Return the time/date value of the list. 

115 

116 This is a compatibility method for the vDDDTypes interface. 

117 

118 Returns: 

119 The first value of the list. 

120 

121 Raises: 

122 IndexError: If the list is empty. 

123 """ 

124 return self.dts[0].dt 

125 

126 def to_xcal(self, element: Element) -> None: 

127 """Convert a vDDDTypes to an xCal element.""" 

128 self.params.to_xcal(element) 

129 for dt in self.dts: 

130 dt.to_xcal(element) 

131 

132 @classmethod 

133 @from_xcal_wrapper 

134 def from_xcal(cls, parser: XCalParser, params: Parameters) -> Self: 

135 """Parse xCal from :rfc:`6321`. 

136 

137 Parameters: 

138 xml: The XML to parse or a parser. 

139 

140 Raises: 

141 ~error.XCalParsingError: If the provided xCal is invalid. 

142 """ 

143 dts = [] 

144 while not parser.is_finished(): 

145 dts.append(vDDDTypes.from_xcal(parser)) 

146 if dts: 

147 tz = getattr(dts[0].dt, "tzinfo", None) 

148 for dt in dts[1:]: 

149 if getattr(dt.dt, "tzinfo", None) != tz: 

150 raise XCalParsingError( 

151 "Cannot mix floating with UTC", None, parser.element 

152 ) 

153 return cls( 

154 dts, 

155 params=params, 

156 ) 

157 

158 

159__all__ = ["vDDDLists"]