Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/cal/availability.py: 56%

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

70 statements  

1"""This implementes the VAVAILABILITY component. 

2 

3This is specified in :rfc:`7953`. 

4""" 

5 

6from __future__ import annotations 

7 

8import uuid 

9from datetime import datetime 

10from typing import TYPE_CHECKING, Optional, Sequence 

11 

12from icalendar.attr import ( 

13 busy_type_property, 

14 categories_property, 

15 class_property, 

16 contacts_property, 

17 description_property, 

18 duration_property, 

19 location_property, 

20 organizer_property, 

21 priority_property, 

22 rfc_7953_dtend_property, 

23 rfc_7953_dtstart_property, 

24 rfc_7953_duration_property, 

25 rfc_7953_end_property, 

26 sequence_property, 

27 summary_property, 

28 url_property, 

29) 

30from icalendar.cal.examples import get_example 

31from icalendar.error import InvalidCalendar 

32 

33from .component import Component 

34 

35if TYPE_CHECKING: 

36 from datetime import date 

37 

38 from icalendar.cal.available import Available 

39 from icalendar.enums import BUSYTYPE, CLASS 

40 from icalendar.prop import vCalAddress 

41 

42 

43class Availability(Component): 

44 """VAVAILABILITY component from :rfc:`7953`. 

45 

46 This provides a grouping of component properties and 

47 subcomponents that describe the availability associated with a 

48 calendar user. 

49 

50 Description: 

51 A "VAVAILABILITY" component indicates a period of time 

52 within which availability information is provided. A 

53 "VAVAILABILITY" component can specify a start time and an end time 

54 or duration. If "DTSTART" is not present, then the start time is 

55 unbounded. If "DTEND" or "DURATION" are not present, then the end 

56 time is unbounded. Within the specified time period, availability 

57 defaults to a free-busy type of "BUSY-UNAVAILABLE" (see 

58 Section 3.2), except for any time periods corresponding to 

59 "AVAILABLE" subcomponents. 

60 

61 "AVAILABLE" subcomponents are used to indicate periods of free 

62 time within the time range of the enclosing "VAVAILABILITY" 

63 component. "AVAILABLE" subcomponents MAY include recurrence 

64 properties to specify recurring periods of time, which can be 

65 overridden using normal iCalendar recurrence behavior (i.e., use 

66 of the "RECURRENCE-ID" property). 

67 

68 If specified, the "DTSTART" and "DTEND" properties in 

69 "VAVAILABILITY" components and "AVAILABLE" subcomponents MUST be 

70 "DATE-TIME" values specified as either the date with UTC time or 

71 the date with local time and a time zone reference. 

72 

73 The iCalendar object containing the "VAVAILABILITY" component MUST 

74 contain appropriate "VTIMEZONE" components corresponding to each 

75 unique "TZID" parameter value used in any DATE-TIME properties in 

76 all components, unless [RFC7809] is in effect. 

77 

78 When used to publish available time, the "ORGANIZER" property 

79 specifies the calendar user associated with the published 

80 available time. 

81 

82 If the "PRIORITY" property is specified in "VAVAILABILITY" 

83 components, it is used to determine how that component is combined 

84 with other "VAVAILABILITY" components. See Section 4. 

85 

86 Other calendar properties MAY be specified in "VAVAILABILITY" or 

87 "AVAILABLE" components and are considered attributes of the marked 

88 block of time. Their usage is application specific. For example, 

89 the "LOCATION" property might be used to indicate that a person is 

90 available in one location for part of the week and a different 

91 location for another part of the week (but see Section 9 for when 

92 it is appropriate to add additional data like this). 

93 

94 Example: 

95 The following is an example of a "VAVAILABILITY" calendar 

96 component used to represent the availability of a user, always 

97 available Monday through Friday, 9:00 am to 5:00 pm in the 

98 America/Montreal time zone: 

99 

100 .. code-block:: text 

101 

102 BEGIN:VAVAILABILITY 

103 ORGANIZER:mailto:bernard@example.com 

104 UID:0428C7D2-688E-4D2E-AC52-CD112E2469DF 

105 DTSTAMP:20111005T133225Z 

106 BEGIN:AVAILABLE 

107 UID:34EDA59B-6BB1-4E94-A66C-64999089C0AF 

108 SUMMARY:Monday to Friday from 9:00 to 17:00 

109 DTSTART;TZID=America/Montreal:20111002T090000 

110 DTEND;TZID=America/Montreal:20111002T170000 

111 RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR 

112 END:AVAILABLE 

113 END:VAVAILABILITY 

114 

115 You can get the same example from :meth:`example`: 

116 

117 .. code-block: pycon 

118 

119 >>> from icalendar import Availability 

120 >>> a = Availability.example() 

121 >>> a.organizer 

122 vCalAddress('mailto:bernard@example.com') 

123 

124 The following is an example of a "VAVAILABILITY" calendar 

125 component used to represent the availability of a user available 

126 Monday through Thursday, 9:00 am to 5:00 pm, at the main office, 

127 and Friday, 9:00 am to 12:00 pm, in the branch office in the 

128 America/Montreal time zone between October 2nd and December 2nd 

129 2011: 

130 

131 .. code-block:: text 

132 

133 BEGIN:VAVAILABILITY 

134 ORGANIZER:mailto:bernard@example.com 

135 UID:84D0F948-7FC6-4C1D-BBF3-BA9827B424B5 

136 DTSTAMP:20111005T133225Z 

137 DTSTART;TZID=America/Montreal:20111002T000000 

138 DTEND;TZID=America/Montreal:20111202T000000 

139 BEGIN:AVAILABLE 

140 UID:7B33093A-7F98-4EED-B381-A5652530F04D 

141 SUMMARY:Monday to Thursday from 9:00 to 17:00 

142 DTSTART;TZID=America/Montreal:20111002T090000 

143 DTEND;TZID=America/Montreal:20111002T170000 

144 RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH 

145 LOCATION:Main Office 

146 END:AVAILABLE 

147 BEGIN:AVAILABLE 

148 UID:DF39DC9E-D8C3-492F-9101-0434E8FC1896 

149 SUMMARY:Friday from 9:00 to 12:00 

150 DTSTART;TZID=America/Montreal:20111006T090000 

151 DTEND;TZID=America/Montreal:20111006T120000 

152 RRULE:FREQ=WEEKLY 

153 LOCATION:Branch Office 

154 END:AVAILABLE 

155 END:VAVAILABILITY 

156 

157 For more examples, have a look at :rfc:`5545`. 

158 

159 """ 

160 

161 name = "VAVAILABILITY" 

162 

163 canonical_order = ( 

164 "DTSTART", 

165 "DTEND", 

166 "DURATION", 

167 "DTSTAMP", 

168 "UID", 

169 "SEQUENCE", 

170 "SUMMARY", 

171 "DESCRIPTION", 

172 "ORGANIZER", 

173 ) 

174 

175 required = ( 

176 "DTSTART", 

177 "DTSTAMP", 

178 "UID", 

179 ) 

180 

181 singletons = ( 

182 "DTSTAMP", 

183 "UID", 

184 "BUSYTYPE", 

185 "CLASS", 

186 "CREATED", 

187 "DESCRIPTION", 

188 "DTSTART", 

189 "LAST-MODIFIED", 

190 "LOCATION", 

191 "ORGANIZER", 

192 "PRIORITY", 

193 "SEQUENCE", 

194 "SUMMARY", 

195 "URL", 

196 "DTEND", 

197 "DURATION", 

198 ) 

199 

200 exclusive = ( 

201 "DTEND", 

202 "DURATION", 

203 ) 

204 

205 organizer = organizer_property 

206 busy_type = busy_type_property 

207 summary = summary_property 

208 description = description_property 

209 sequence = sequence_property 

210 classification = class_property 

211 url = url_property 

212 location = location_property 

213 categories = categories_property 

214 priority = priority_property 

215 contacts = contacts_property 

216 

217 start = DTSTART = rfc_7953_dtstart_property 

218 DTEND = rfc_7953_dtend_property 

219 DURATION = duration_property("Availability") 

220 duration = rfc_7953_duration_property 

221 end = rfc_7953_end_property 

222 

223 @property 

224 def available(self) -> list[Available]: 

225 """All VAVAILABLE sub-components. 

226 

227 This is a shortcut to get all VAVAILABLE sub-components. 

228 Modifications do not change the calendar. 

229 Use :py:meth:`Component.add_component`. 

230 """ 

231 return self.walk("VAVAILABLE") 

232 

233 @classmethod 

234 def new( 

235 cls, 

236 /, 

237 busy_type: Optional[BUSYTYPE] = None, 

238 categories: Sequence[str] = (), 

239 comments: list[str] | str | None = None, 

240 components: Sequence[Available] | None = (), 

241 contacts: list[str] | str | None = None, 

242 created: Optional[date] = None, 

243 classification: Optional[CLASS] = None, 

244 description: Optional[str] = None, 

245 end: Optional[datetime] = None, 

246 last_modified: Optional[date] = None, 

247 location: Optional[str] = None, 

248 organizer: Optional[vCalAddress | str] = None, 

249 priority: Optional[int] = None, 

250 sequence: Optional[int] = None, 

251 stamp: Optional[date] = None, 

252 start: Optional[datetime] = None, 

253 summary: Optional[str] = None, 

254 uid: Optional[str | uuid.UUID] = None, 

255 url: Optional[str] = None, 

256 ): 

257 """Create a new event with all required properties. 

258 

259 This creates a new Availability in accordance with :rfc:`7953`. 

260 

261 Arguments: 

262 busy_type: The :attr:`busy_type` of the availability. 

263 categories: The :attr:`categories` of the availability. 

264 classification: The :attr:`classification` of the availability. 

265 comments: The :attr:`Component.comments` of the availability. 

266 contacts: The :attr:`contacts` of the availability. 

267 created: The :attr:`Component.created` of the availability. 

268 description: The :attr:`description` of the availability. 

269 last_modified: The :attr:`Component.last_modified` of the availability. 

270 location: The :attr:`location` of the availability. 

271 organizer: The :attr:`organizer` of the availability. 

272 sequence: The :attr:`sequence` of the availability. 

273 stamp: The :attr:`Component.stamp` of the availability. 

274 If None, this is set to the current time. 

275 summary: The :attr:`summary` of the availability. 

276 uid: The :attr:`uid` of the availability. 

277 If None, this is set to a new :func:`uuid.uuid4`. 

278 url: The :attr:`url` of the availability. 

279 

280 Returns: 

281 :class:`Availability` 

282 

283 Raises: 

284 InvalidCalendar: If the content is not valid according to :rfc:`7953`. 

285 

286 .. warning:: As time progresses, we will be stricter with the validation. 

287 """ 

288 availability = super().new( 

289 stamp=stamp if stamp is not None else cls._utc_now(), 

290 created=created, 

291 last_modified=last_modified, 

292 ) 

293 availability.summary = summary 

294 availability.description = description 

295 availability.uid = uid if uid is not None else uuid.uuid4() 

296 availability.sequence = sequence 

297 availability.categories = categories 

298 availability.classification = classification 

299 availability.url = url 

300 availability.busy_type = busy_type 

301 availability.organizer = organizer 

302 availability.location = location 

303 availability.comments = comments 

304 availability.priority = priority 

305 availability.contacts = contacts 

306 for subcomponent in components: 

307 availability.add_component(subcomponent) 

308 if cls._validate_new: 

309 if start is not None and ( 

310 not isinstance(start, datetime) or start.tzinfo is None 

311 ): 

312 raise InvalidCalendar( 

313 "Availability start must be a datetime with a timezone" 

314 ) 

315 if end is not None and ( 

316 not isinstance(end, datetime) or end.tzinfo is None 

317 ): 

318 raise InvalidCalendar( 

319 "Availability end must be a datetime with a timezone" 

320 ) 

321 availability._validate_start_and_end(start, end) # noqa: SLF001 

322 availability.start = start 

323 availability.end = end 

324 return availability 

325 

326 @classmethod 

327 def example(cls, name: str = "rfc_7953_1") -> Availability: 

328 """Return the calendar example with the given name.""" 

329 return cls.from_ical(get_example("availabilities", name)) 

330 

331 

332__all__ = ["Availability"]