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

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

69 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 CONCEPTS_TYPE_SETTER, 

14 LINKS_TYPE_SETTER, 

15 RELATED_TO_TYPE_SETTER, 

16 busy_type_property, 

17 categories_property, 

18 class_property, 

19 contacts_property, 

20 description_property, 

21 duration_property, 

22 location_property, 

23 organizer_property, 

24 priority_property, 

25 rfc_7953_dtend_property, 

26 rfc_7953_dtstart_property, 

27 rfc_7953_duration_property, 

28 rfc_7953_end_property, 

29 sequence_property, 

30 summary_property, 

31 url_property, 

32) 

33from icalendar.cal.examples import get_example 

34from icalendar.error import InvalidCalendar 

35 

36from .component import Component 

37 

38if TYPE_CHECKING: 

39 from datetime import date 

40 

41 from icalendar.cal.available import Available 

42 from icalendar.enums import BUSYTYPE, CLASS 

43 from icalendar.prop import vCalAddress 

44 

45 

46class Availability(Component): 

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

48 

49 This provides a grouping of component properties and 

50 subcomponents that describe the availability associated with a 

51 calendar user. 

52 

53 Description: 

54 A "VAVAILABILITY" component indicates a period of time 

55 within which availability information is provided. A 

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

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

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

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

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

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

62 "AVAILABLE" subcomponents. 

63 

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

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

66 component. "AVAILABLE" subcomponents MAY include recurrence 

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

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

69 of the "RECURRENCE-ID" property). 

70 

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

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

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

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

75 

76 The iCalendar object containing the "VAVAILABILITY" component MUST 

77 contain appropriate "VTIMEZONE" components corresponding to each 

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

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

80 

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

82 specifies the calendar user associated with the published 

83 available time. 

84 

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

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

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

88 

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

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

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

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

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

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

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

96 

97 Example: 

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

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

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

101 America/Montreal time zone: 

102 

103 .. code-block:: text 

104 

105 BEGIN:VAVAILABILITY 

106 ORGANIZER:mailto:bernard@example.com 

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

108 DTSTAMP:20111005T133225Z 

109 BEGIN:AVAILABLE 

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

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

112 DTSTART;TZID=America/Montreal:20111002T090000 

113 DTEND;TZID=America/Montreal:20111002T170000 

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

115 END:AVAILABLE 

116 END:VAVAILABILITY 

117 

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

119 

120 .. code-block: pycon 

121 

122 >>> from icalendar import Availability 

123 >>> a = Availability.example() 

124 >>> a.organizer 

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

126 

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

128 component used to represent the availability of a user available 

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

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

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

132 2011: 

133 

134 .. code-block:: text 

135 

136 BEGIN:VAVAILABILITY 

137 ORGANIZER:mailto:bernard@example.com 

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

139 DTSTAMP:20111005T133225Z 

140 DTSTART;TZID=America/Montreal:20111002T000000 

141 DTEND;TZID=America/Montreal:20111202T000000 

142 BEGIN:AVAILABLE 

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

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

145 DTSTART;TZID=America/Montreal:20111002T090000 

146 DTEND;TZID=America/Montreal:20111002T170000 

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

148 LOCATION:Main Office 

149 END:AVAILABLE 

150 BEGIN:AVAILABLE 

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

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

153 DTSTART;TZID=America/Montreal:20111006T090000 

154 DTEND;TZID=America/Montreal:20111006T120000 

155 RRULE:FREQ=WEEKLY 

156 LOCATION:Branch Office 

157 END:AVAILABLE 

158 END:VAVAILABILITY 

159 

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

161 

162 """ 

163 

164 name = "VAVAILABILITY" 

165 

166 canonical_order = ( 

167 "DTSTART", 

168 "DTEND", 

169 "DURATION", 

170 "DTSTAMP", 

171 "UID", 

172 "SEQUENCE", 

173 "SUMMARY", 

174 "DESCRIPTION", 

175 "ORGANIZER", 

176 ) 

177 

178 required = ( 

179 "DTSTART", 

180 "DTSTAMP", 

181 "UID", 

182 ) 

183 

184 singletons = ( 

185 "DTSTAMP", 

186 "UID", 

187 "BUSYTYPE", 

188 "CLASS", 

189 "CREATED", 

190 "DESCRIPTION", 

191 "DTSTART", 

192 "LAST-MODIFIED", 

193 "LOCATION", 

194 "ORGANIZER", 

195 "PRIORITY", 

196 "SEQUENCE", 

197 "SUMMARY", 

198 "URL", 

199 "DTEND", 

200 "DURATION", 

201 ) 

202 

203 exclusive = ( 

204 "DTEND", 

205 "DURATION", 

206 ) 

207 

208 organizer = organizer_property 

209 busy_type = busy_type_property 

210 summary = summary_property 

211 description = description_property 

212 sequence = sequence_property 

213 classification = class_property 

214 url = url_property 

215 location = location_property 

216 categories = categories_property 

217 priority = priority_property 

218 contacts = contacts_property 

219 

220 start = DTSTART = rfc_7953_dtstart_property 

221 DTEND = rfc_7953_dtend_property 

222 DURATION = duration_property("Availability") 

223 duration = rfc_7953_duration_property 

224 end = rfc_7953_end_property 

225 

226 @property 

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

228 """All VAVAILABLE sub-components. 

229 

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

231 Modifications do not change the calendar. 

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

233 """ 

234 return self.walk("VAVAILABLE") 

235 

236 @classmethod 

237 def new( 

238 cls, 

239 /, 

240 busy_type: Optional[BUSYTYPE] = None, 

241 categories: Sequence[str] = (), 

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

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

244 concepts: CONCEPTS_TYPE_SETTER = None, 

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

246 created: Optional[date] = None, 

247 classification: Optional[CLASS] = None, 

248 description: Optional[str] = None, 

249 end: Optional[datetime] = None, 

250 last_modified: Optional[date] = None, 

251 links: LINKS_TYPE_SETTER = None, 

252 location: Optional[str] = None, 

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

254 priority: Optional[int] = None, 

255 refids: list[str] | str | None = None, 

256 related_to: RELATED_TO_TYPE_SETTER = None, 

257 sequence: Optional[int] = None, 

258 stamp: Optional[date] = None, 

259 start: Optional[datetime] = None, 

260 summary: Optional[str] = None, 

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

262 url: Optional[str] = None, 

263 ): 

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

265 

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

267 

268 Arguments: 

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

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

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

272 comments: The :attr:`~icalendar.Component.comments` of the availability. 

273 concepts: The :attr:`~icalendar.Component.concepts` of the availability. 

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

275 created: The :attr:`~icalendar.Component.created` of the availability. 

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

277 end: The :attr:`end` of the availability. 

278 last_modified: The :attr:`~icalendar.Component.last_modified` of the 

279 availability. 

280 links: The :attr:`~icalendar.Component.links` of the availability. 

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

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

283 refids: :attr:`~icalendar.Component.refids` of the availability. 

284 related_to: :attr:`~icalendar.Component.related_to` of the availability. 

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

286 stamp: The :attr:`~icalendar.Component.stamp` of the availability. 

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

288 start: The :attr:`start` of the availability. 

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

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

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

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

293 

294 Returns: 

295 :class:`Availability` 

296 

297 Raises: 

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

299 

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

301 """ 

302 availability: Availability = super().new( 

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

304 created=created, 

305 comments=comments, 

306 last_modified=last_modified, 

307 links=links, 

308 related_to=related_to, 

309 refids=refids, 

310 concepts=concepts, 

311 ) 

312 availability.summary = summary 

313 availability.description = description 

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

315 availability.sequence = sequence 

316 availability.categories = categories 

317 availability.classification = classification 

318 availability.url = url 

319 availability.busy_type = busy_type 

320 availability.organizer = organizer 

321 availability.location = location 

322 availability.priority = priority 

323 availability.contacts = contacts 

324 for subcomponent in components: 

325 availability.add_component(subcomponent) 

326 if cls._validate_new: 

327 if start is not None and ( 

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

329 ): 

330 raise InvalidCalendar( 

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

332 ) 

333 if end is not None and ( 

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

335 ): 

336 raise InvalidCalendar( 

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

338 ) 

339 availability._validate_start_and_end(start, end) 

340 availability.start = start 

341 availability.end = end 

342 return availability 

343 

344 @classmethod 

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

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

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

348 

349 

350__all__ = ["Availability"]