Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/attr.py: 35%
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
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
1"""Attributes of Components and properties."""
3from __future__ import annotations
5import itertools
6from datetime import date, datetime, timedelta
7from typing import TYPE_CHECKING, Optional, Sequence, Union
9from icalendar.enums import BUSYTYPE, CLASS, STATUS, TRANSP, StrEnum
10from icalendar.error import IncompleteComponent, InvalidCalendar
11from icalendar.parser_tools import SEQUENCE_TYPES
12from icalendar.prop import vCalAddress, vCategory, vDDDTypes, vDuration, vRecur, vText
13from icalendar.timezone import tzp
15if TYPE_CHECKING:
16 from icalendar.cal import Component
19def _get_rdates(
20 self: Component,
21) -> list[Union[tuple[date, None], tuple[datetime, None], tuple[datetime, datetime]]]:
22 """The RDATE property defines the list of DATE-TIME values for recurring components.
24 RDATE is defined in :rfc:`5545`.
25 The return value is a list of tuples ``(start, end)``.
27 ``start`` can be a :class:`datetime.date` or a :class:`datetime.datetime`,
28 with and without timezone.
30 ``end`` is :obj:`None` if the end is not specified and a :class:`datetime.datetime`
31 if the end is specified.
33 Value Type:
34 The default value type for this property is DATE-TIME.
35 The value type can be set to DATE or PERIOD.
37 Property Parameters:
38 IANA, non-standard, value data type, and time
39 zone identifier property parameters can be specified on this
40 property.
42 Conformance:
43 This property can be specified in recurring "VEVENT",
44 "VTODO", and "VJOURNAL" calendar components as well as in the
45 "STANDARD" and "DAYLIGHT" sub-components of the "VTIMEZONE"
46 calendar component.
48 Description:
49 This property can appear along with the "RRULE"
50 property to define an aggregate set of repeating occurrences.
51 When they both appear in a recurring component, the recurrence
52 instances are defined by the union of occurrences defined by both
53 the "RDATE" and "RRULE".
55 The recurrence dates, if specified, are used in computing the
56 recurrence set. The recurrence set is the complete set of
57 recurrence instances for a calendar component. The recurrence set
58 is generated by considering the initial "DTSTART" property along
59 with the "RRULE", "RDATE", and "EXDATE" properties contained
60 within the recurring component. The "DTSTART" property defines
61 the first instance in the recurrence set. The "DTSTART" property
62 value SHOULD match the pattern of the recurrence rule, if
63 specified. The recurrence set generated with a "DTSTART" property
64 value that doesn't match the pattern of the rule is undefined.
65 The final recurrence set is generated by gathering all of the
66 start DATE-TIME values generated by any of the specified "RRULE"
67 and "RDATE" properties, and then excluding any start DATE-TIME
68 values specified by "EXDATE" properties. This implies that start
69 DATE-TIME values specified by "EXDATE" properties take precedence
70 over those specified by inclusion properties (i.e., "RDATE" and
71 "RRULE"). Where duplicate instances are generated by the "RRULE"
72 and "RDATE" properties, only one recurrence is considered.
73 Duplicate instances are ignored.
75 Example:
76 Below, we set one RDATE in a list and get the resulting tuple of start and end.
78 .. code-block:: pycon
80 >>> from icalendar import Event
81 >>> from datetime import datetime
82 >>> event = Event()
84 # Add a list of recurrence dates
85 >>> event.add("RDATE", [datetime(2025, 4, 28, 16, 5)])
86 >>> event.rdates
87 [(datetime.datetime(2025, 4, 28, 16, 5), None)]
89 .. note::
91 You cannot modify the RDATE value by modifying the result.
92 Use :func:`icalendar.cal.Component.add` to add values.
94 If you want to compute recurrences, have a look at :ref:`Related projects`.
96 """
97 result = []
98 rdates = self.get("RDATE", [])
99 for rdates in (rdates,) if not isinstance(rdates, list) else rdates:
100 for dts in rdates.dts:
101 rdate = dts.dt
102 if isinstance(rdate, tuple):
103 # we have a period as rdate
104 if isinstance(rdate[1], timedelta):
105 result.append((rdate[0], rdate[0] + rdate[1]))
106 else:
107 result.append(rdate)
108 else:
109 # we have a date/datetime
110 result.append((rdate, None))
111 return result
114rdates_property = property(_get_rdates)
117def _get_exdates(self: Component) -> list[date | datetime]:
118 """EXDATE defines the list of DATE-TIME exceptions for recurring components.
120 EXDATE is defined in :rfc:`5545`.
122 Value Type:
123 The default value type for this property is DATE-TIME.
124 The value type can be set to DATE.
126 Property Parameters:
127 IANA, non-standard, value data type, and time
128 zone identifier property parameters can be specified on this
129 property.
131 Conformance:
132 This property can be specified in recurring "VEVENT",
133 "VTODO", and "VJOURNAL" calendar components as well as in the
134 "STANDARD" and "DAYLIGHT" sub-components of the "VTIMEZONE"
135 calendar component.
137 Description:
138 The exception dates, if specified, are used in
139 computing the recurrence set. The recurrence set is the complete
140 set of recurrence instances for a calendar component. The
141 recurrence set is generated by considering the initial "DTSTART"
142 property along with the "RRULE", "RDATE", and "EXDATE" properties
143 contained within the recurring component. The "DTSTART" property
144 defines the first instance in the recurrence set. The "DTSTART"
145 property value SHOULD match the pattern of the recurrence rule, if
146 specified. The recurrence set generated with a "DTSTART" property
147 value that doesn't match the pattern of the rule is undefined.
148 The final recurrence set is generated by gathering all of the
149 start DATE-TIME values generated by any of the specified "RRULE"
150 and "RDATE" properties, and then excluding any start DATE-TIME
151 values specified by "EXDATE" properties. This implies that start
152 DATE-TIME values specified by "EXDATE" properties take precedence
153 over those specified by inclusion properties (i.e., "RDATE" and
154 "RRULE"). When duplicate instances are generated by the "RRULE"
155 and "RDATE" properties, only one recurrence is considered.
156 Duplicate instances are ignored.
158 The "EXDATE" property can be used to exclude the value specified
159 in "DTSTART". However, in such cases, the original "DTSTART" date
160 MUST still be maintained by the calendaring and scheduling system
161 because the original "DTSTART" value has inherent usage
162 dependencies by other properties such as the "RECURRENCE-ID".
164 Example:
165 Below, we add an exdate in a list and get the resulting list of exdates.
167 .. code-block:: pycon
169 >>> from icalendar import Event
170 >>> from datetime import datetime
171 >>> event = Event()
173 # Add a list of excluded dates
174 >>> event.add("EXDATE", [datetime(2025, 4, 28, 16, 5)])
175 >>> event.exdates
176 [datetime.datetime(2025, 4, 28, 16, 5)]
178 .. note::
180 You cannot modify the EXDATE value by modifying the result.
181 Use :func:`icalendar.cal.Component.add` to add values.
183 If you want to compute recurrences, have a look at :ref:`Related projects`.
185 """
186 result = []
187 exdates = self.get("EXDATE", [])
188 for exdates in (exdates,) if not isinstance(exdates, list) else exdates:
189 for dts in exdates.dts:
190 exdate = dts.dt
191 # we have a date/datetime
192 result.append(exdate)
193 return result
196exdates_property = property(_get_exdates)
199def _get_rrules(self: Component) -> list[vRecur]:
200 """RRULE defines a rule or repeating pattern for recurring components.
202 RRULE is defined in :rfc:`5545`.
203 :rfc:`7529` adds the ``SKIP`` parameter :class:`icalendar.prop.vSkip`.
205 Property Parameters:
206 IANA and non-standard property parameters can
207 be specified on this property.
209 Conformance:
210 This property can be specified in recurring "VEVENT",
211 "VTODO", and "VJOURNAL" calendar components as well as in the
212 "STANDARD" and "DAYLIGHT" sub-components of the "VTIMEZONE"
213 calendar component, but it SHOULD NOT be specified more than once.
214 The recurrence set generated with multiple "RRULE" properties is
215 undefined.
217 Description:
218 The recurrence rule, if specified, is used in computing
219 the recurrence set. The recurrence set is the complete set of
220 recurrence instances for a calendar component. The recurrence set
221 is generated by considering the initial "DTSTART" property along
222 with the "RRULE", "RDATE", and "EXDATE" properties contained
223 within the recurring component. The "DTSTART" property defines
224 the first instance in the recurrence set. The "DTSTART" property
225 value SHOULD be synchronized with the recurrence rule, if
226 specified. The recurrence set generated with a "DTSTART" property
227 value not synchronized with the recurrence rule is undefined. The
228 final recurrence set is generated by gathering all of the start
229 DATE-TIME values generated by any of the specified "RRULE" and
230 "RDATE" properties, and then excluding any start DATE-TIME values
231 specified by "EXDATE" properties. This implies that start DATE-
232 TIME values specified by "EXDATE" properties take precedence over
233 those specified by inclusion properties (i.e., "RDATE" and
234 "RRULE"). Where duplicate instances are generated by the "RRULE"
235 and "RDATE" properties, only one recurrence is considered.
236 Duplicate instances are ignored.
238 The "DTSTART" property specified within the iCalendar object
239 defines the first instance of the recurrence. In most cases, a
240 "DTSTART" property of DATE-TIME value type used with a recurrence
241 rule, should be specified as a date with local time and time zone
242 reference to make sure all the recurrence instances start at the
243 same local time regardless of time zone changes.
245 If the duration of the recurring component is specified with the
246 "DTEND" or "DUE" property, then the same exact duration will apply
247 to all the members of the generated recurrence set. Else, if the
248 duration of the recurring component is specified with the
249 "DURATION" property, then the same nominal duration will apply to
250 all the members of the generated recurrence set and the exact
251 duration of each recurrence instance will depend on its specific
252 start time. For example, recurrence instances of a nominal
253 duration of one day will have an exact duration of more or less
254 than 24 hours on a day where a time zone shift occurs. The
255 duration of a specific recurrence may be modified in an exception
256 component or simply by using an "RDATE" property of PERIOD value
257 type.
259 Examples:
260 Daily for 10 occurrences:
262 .. code-block:: pycon
264 >>> from icalendar import Event
265 >>> from datetime import datetime
266 >>> from zoneinfo import ZoneInfo
267 >>> event = Event()
268 >>> event.start = datetime(1997, 9, 2, 9, 0, tzinfo=ZoneInfo("America/New_York"))
269 >>> event.add("RRULE", "FREQ=DAILY;COUNT=10")
270 >>> print(event.to_ical())
271 BEGIN:VEVENT
272 DTSTART;TZID=America/New_York:19970902T090000
273 RRULE:FREQ=DAILY;COUNT=10
274 END:VEVENT
275 >>> event.rrules
276 [vRecur({'FREQ': ['DAILY'], 'COUNT': [10]})]
278 Daily until December 24, 1997:
280 .. code-block:: pycon
282 >>> from icalendar import Event, vRecur
283 >>> from datetime import datetime
284 >>> from zoneinfo import ZoneInfo
285 >>> event = Event()
286 >>> event.start = datetime(1997, 9, 2, 9, 0, tzinfo=ZoneInfo("America/New_York"))
287 >>> event.add("RRULE", vRecur({"FREQ": ["DAILY"]}, until=datetime(1997, 12, 24, tzinfo=ZoneInfo("UTC"))))
288 >>> print(event.to_ical())
289 BEGIN:VEVENT
290 DTSTART;TZID=America/New_York:19970902T090000
291 RRULE:FREQ=DAILY;UNTIL=19971224T000000Z
292 END:VEVENT
293 >>> event.rrules
294 [vRecur({'FREQ': ['DAILY'], 'UNTIL': [datetime.datetime(1997, 12, 24, 0, 0, tzinfo=ZoneInfo(key='UTC'))]})]
296 .. note::
298 You cannot modify the RRULE value by modifying the result.
299 Use :func:`icalendar.cal.Component.add` to add values.
301 If you want to compute recurrences, have a look at :ref:`Related projects`.
303 """ # noqa: E501
304 rrules = self.get("RRULE", [])
305 if not isinstance(rrules, list):
306 return [rrules]
307 return rrules
310rrules_property = property(_get_rrules)
313def multi_language_text_property(
314 main_prop: str, compatibility_prop: Optional[str], doc: str
315) -> property:
316 """This creates a text property.
318 This property can be defined several times with different ``LANGUAGE`` parameters.
320 Args:
321 main_prop (str): The property to set and get, such as ``NAME``
322 compatibility_prop (str): An old property used before, such as ``X-WR-CALNAME``
323 doc (str): The documentation string
324 """
326 def fget(self: Component) -> Optional[str]:
327 """Get the property"""
328 result = self.get(main_prop)
329 if result is None and compatibility_prop is not None:
330 result = self.get(compatibility_prop)
331 if isinstance(result, list):
332 for item in result:
333 if "LANGUAGE" not in item.params:
334 return item
335 return result
337 def fset(self: Component, value: Optional[str]):
338 """Set the property."""
339 fdel(self)
340 if value is not None:
341 self.add(main_prop, value)
343 def fdel(self: Component):
344 """Delete the property."""
345 self.pop(main_prop, None)
346 if compatibility_prop is not None:
347 self.pop(compatibility_prop, None)
349 return property(fget, fset, fdel, doc)
352def single_int_property(prop: str, default: int, doc: str) -> property:
353 """Create a property for an int value that exists only once.
355 Args:
356 prop: The name of the property
357 default: The default value
358 doc: The documentation string
359 """
361 def fget(self: Component) -> int:
362 """Get the property"""
363 try:
364 return int(self.get(prop, default))
365 except ValueError as e:
366 raise InvalidCalendar(f"{prop} must be an int") from e
368 def fset(self: Component, value: Optional[int]):
369 """Set the property."""
370 fdel(self)
371 if value is not None:
372 self.add(prop, value)
374 def fdel(self: Component):
375 """Delete the property."""
376 self.pop(prop, None)
378 return property(fget, fset, fdel, doc)
381def single_utc_property(name: str, docs: str) -> property:
382 """Create a property to access a value of datetime in UTC timezone.
384 Args:
385 name: name of the property
386 docs: documentation string
387 """
388 docs = (
389 f"""The {name} property. datetime in UTC
391 All values will be converted to a datetime in UTC.
392 """
393 + docs
394 )
396 def fget(self: Component) -> Optional[datetime]:
397 """Get the value."""
398 if name not in self:
399 return None
400 dt = self.get(name)
401 if isinstance(dt, vText):
402 # we might be in an attribute that is not typed
403 value = vDDDTypes.from_ical(dt)
404 else:
405 value = getattr(dt, "dt", dt)
406 if value is None or not isinstance(value, date):
407 raise InvalidCalendar(f"{name} must be a datetime in UTC, not {value}")
408 return tzp.localize_utc(value)
410 def fset(self: Component, value: Optional[datetime]):
411 """Set the value"""
412 if value is None:
413 fdel(self)
414 return
415 if not isinstance(value, date):
416 raise TypeError(f"{name} takes a datetime in UTC, not {value}")
417 fdel(self)
418 self.add(name, tzp.localize_utc(value))
420 def fdel(self: Component):
421 """Delete the property."""
422 self.pop(name, None)
424 return property(fget, fset, fdel, doc=docs)
427def single_string_property(
428 name: str, docs: str, other_name: Optional[str] = None, default: str = ""
429) -> property:
430 """Create a property to access a single string value."""
432 def fget(self: Component) -> str:
433 """Get the value."""
434 result = self.get(
435 name, None if other_name is None else self.get(other_name, None)
436 )
437 if result is None or result == []:
438 return default
439 if isinstance(result, list):
440 return result[0]
441 return result
443 def fset(self: Component, value: Optional[str]):
444 """Set the value.
446 Setting the value to None will delete it.
447 """
448 fdel(self)
449 if value is not None:
450 self.add(name, value)
452 def fdel(self: Component):
453 """Delete the property."""
454 self.pop(name, None)
455 if other_name is not None:
456 self.pop(other_name, None)
458 return property(fget, fset, fdel, doc=docs)
461color_property = single_string_property(
462 "COLOR",
463 """This property specifies a color used for displaying the component.
465 This implements :rfc:`7986` ``COLOR`` property.
467 Property Parameters:
468 IANA and non-standard property parameters can
469 be specified on this property.
471 Conformance:
472 This property can be specified once in an iCalendar
473 object or in ``VEVENT``, ``VTODO``, or ``VJOURNAL`` calendar components.
475 Description:
476 This property specifies a color that clients MAY use
477 when presenting the relevant data to a user. Typically, this
478 would appear as the "background" color of events or tasks. The
479 value is a case-insensitive color name taken from the CSS3 set of
480 names, defined in Section 4.3 of `W3C.REC-css3-color-20110607 <https://www.w3.org/TR/css-color-3/>`_.
482 Example:
483 ``"turquoise"``, ``"#ffffff"``
485 .. code-block:: pycon
487 >>> from icalendar import Todo
488 >>> todo = Todo()
489 >>> todo.color = "green"
490 >>> print(todo.to_ical())
491 BEGIN:VTODO
492 COLOR:green
493 END:VTODO
494 """,
495)
497sequence_property = single_int_property(
498 "SEQUENCE",
499 0,
500 """This property defines the revision sequence number of the calendar component within a sequence of revisions.
502Value Type:
503 INTEGER
505Property Parameters:
506 IANA and non-standard property parameters can be specified on this property.
508Conformance:
509 The property can be specified in "VEVENT", "VTODO", or
510 "VJOURNAL" calendar component.
512Description:
513 When a calendar component is created, its sequence
514 number is 0. It is monotonically incremented by the "Organizer's"
515 CUA each time the "Organizer" makes a significant revision to the
516 calendar component.
518 The "Organizer" includes this property in an iCalendar object that
519 it sends to an "Attendee" to specify the current version of the
520 calendar component.
522 The "Attendee" includes this property in an iCalendar object that
523 it sends to the "Organizer" to specify the version of the calendar
524 component to which the "Attendee" is referring.
526 A change to the sequence number is not the mechanism that an
527 "Organizer" uses to request a response from the "Attendees". The
528 "RSVP" parameter on the "ATTENDEE" property is used by the
529 "Organizer" to indicate that a response from the "Attendees" is
530 requested.
532 Recurrence instances of a recurring component MAY have different
533 sequence numbers.
535Examples:
536 The following is an example of this property for a calendar
537 component that was just created by the "Organizer":
539 .. code-block:: pycon
541 >>> from icalendar import Event
542 >>> event = Event()
543 >>> event.sequence
544 0
546 The following is an example of this property for a calendar
547 component that has been revised 10 different times by the
548 "Organizer":
550 .. code-block:: pycon
552 >>> from icalendar import Calendar
553 >>> calendar = Calendar.example("issue_156_RDATE_with_PERIOD_TZID_khal")
554 >>> event = calendar.events[0]
555 >>> event.sequence
556 10
557 """, # noqa: E501
558)
561def _get_categories(component: Component) -> list[str]:
562 """Get all the categories."""
563 categories: Optional[vCategory | list[vCategory]] = component.get("CATEGORIES")
564 if isinstance(categories, list):
565 _set_categories(
566 component,
567 list(itertools.chain.from_iterable(cat.cats for cat in categories)),
568 )
569 return _get_categories(component)
570 if categories is None:
571 categories = vCategory([])
572 component.add("CATEGORIES", categories)
573 return categories.cats
576def _set_categories(component: Component, cats: Optional[Sequence[str]]) -> None:
577 """Set the categories."""
578 if not cats and cats != []:
579 _del_categories(component)
580 return
581 component["CATEGORIES"] = categories = vCategory(cats)
582 if isinstance(cats, list):
583 cats.clear()
584 cats.extend(categories.cats)
585 categories.cats = cats
588def _del_categories(component: Component) -> None:
589 """Delete the categories."""
590 component.pop("CATEGORIES", None)
593categories_property = property(
594 _get_categories,
595 _set_categories,
596 _del_categories,
597 """This property defines the categories for a component.
599Property Parameters:
600 IANA, non-standard, and language property parameters can be specified on this
601 property.
603Conformance:
604 The property can be specified within "VEVENT", "VTODO", or "VJOURNAL" calendar
605 components.
606 Since :rfc:`7986` it can also be defined on a "VCALENDAR" component.
608Description:
609 This property is used to specify categories or subtypes
610 of the calendar component. The categories are useful in searching
611 for a calendar component of a particular type and category.
612 Within the "VEVENT", "VTODO", or "VJOURNAL" calendar components,
613 more than one category can be specified as a COMMA-separated list
614 of categories.
616Example:
617 Below, we add the categories to an event:
619 .. code-block:: pycon
621 >>> from icalendar import Event
622 >>> event = Event()
623 >>> event.categories = ["Work", "Meeting"]
624 >>> print(event.to_ical())
625 BEGIN:VEVENT
626 CATEGORIES:Work,Meeting
627 END:VEVENT
628 >>> event.categories.append("Lecture")
629 >>> event.categories == ["Work", "Meeting", "Lecture"]
630 True
632.. note::
634 At present, we do not take the LANGUAGE parameter into account.
635""",
636)
639def _get_attendees(self: Component) -> list[vCalAddress]:
640 """Get attendees."""
641 value = self.get("ATTENDEE")
642 if value is None:
643 value = []
644 self["ATTENDEE"] = value
645 return value
646 if isinstance(value, vCalAddress):
647 return [value]
648 return value
651def _set_attendees(self: Component, value: list[vCalAddress] | vCalAddress | None):
652 """Set attendees."""
653 _del_attendees(self)
654 if value is None:
655 return
656 if not isinstance(value, list):
657 value = [value]
658 self["ATTENDEE"] = value
661def _del_attendees(self: Component):
662 """Delete all attendees."""
663 self.pop("ATTENDEE", None)
666attendees_property = property(
667 _get_attendees,
668 _set_attendees,
669 _del_attendees,
670 """ATTENDEE defines one or more "Attendees" within a calendar component.
672Conformance:
673 This property MUST be specified in an iCalendar object
674 that specifies a group-scheduled calendar entity. This property
675 MUST NOT be specified in an iCalendar object when publishing the
676 calendar information (e.g., NOT in an iCalendar object that
677 specifies the publication of a calendar user's busy time, event,
678 to-do, or journal). This property is not specified in an
679 iCalendar object that specifies only a time zone definition or
680 that defines calendar components that are not group-scheduled
681 components, but are components only on a single user's calendar.
683Description:
684 This property MUST only be specified within calendar
685 components to specify participants, non-participants, and the
686 chair of a group-scheduled calendar entity. The property is
687 specified within an "EMAIL" category of the "VALARM" calendar
688 component to specify an email address that is to receive the email
689 type of iCalendar alarm.
691Examples:
692 Add a new attendee to an existing event.
694 .. code-block:: pycon
696 >>> from icalendar import Event, vCalAddress
697 >>> event = Event()
698 >>> event.attendees.append(vCalAddress("mailto:me@my-domain.com"))
699 >>> print(event.to_ical())
700 BEGIN:VEVENT
701 ATTENDEE:mailto:me@my-domain.com
702 END:VEVENT
704 Create an email alarm with several attendees:
706 >>> from icalendar import Alarm, vCalAddress
707 >>> alarm = Alarm.new(attendees = [
708 ... vCalAddress("mailto:me@my-domain.com"),
709 ... vCalAddress("mailto:you@my-domain.com"),
710 ... ], summary = "Email alarm")
711 >>> print(alarm.to_ical())
712 BEGIN:VALARM
713 ATTENDEE:mailto:me@my-domain.com
714 ATTENDEE:mailto:you@my-domain.com
715 SUMMARY:Email alarm
716 END:VALARM
717""",
718)
720uid_property = single_string_property(
721 "UID",
722 """UID specifies the persistent, globally unique identifier for a component.
724We recommend using :func:`uuid.uuid4` to generate new values.
726Returns:
727 The value of the UID property as a string or ``""`` if no value is set.
729Description:
730 The "UID" itself MUST be a globally unique identifier.
731 The generator of the identifier MUST guarantee that the identifier
732 is unique.
734 This is the method for correlating scheduling messages with the
735 referenced "VEVENT", "VTODO", or "VJOURNAL" calendar component.
736 The full range of calendar components specified by a recurrence
737 set is referenced by referring to just the "UID" property value
738 corresponding to the calendar component. The "RECURRENCE-ID"
739 property allows the reference to an individual instance within the
740 recurrence set.
742 This property is an important method for group-scheduling
743 applications to match requests with later replies, modifications,
744 or deletion requests. Calendaring and scheduling applications
745 MUST generate this property in "VEVENT", "VTODO", and "VJOURNAL"
746 calendar components to assure interoperability with other group-
747 scheduling applications. This identifier is created by the
748 calendar system that generates an iCalendar object.
750 Implementations MUST be able to receive and persist values of at
751 least 255 octets for this property, but they MUST NOT truncate
752 values in the middle of a UTF-8 multi-octet sequence.
754 :rfc:`7986` states that UID can be used, for
755 example, to identify duplicate calendar streams that a client may
756 have been given access to. It can be used in conjunction with the
757 "LAST-MODIFIED" property also specified on the "VCALENDAR" object
758 to identify the most recent version of a calendar.
760Conformance:
761 :rfc:`5545` states that the "UID" property can be specified on "VEVENT", "VTODO",
762 and "VJOURNAL" calendar components.
763 :rfc:`7986` modifies the definition of the "UID" property to
764 allow it to be defined in an iCalendar object.
765 :rfc:`9074` adds a "UID" property to "VALARM" components to allow a unique
766 identifier to be specified. The value of this property can then be used
767 to refer uniquely to the "VALARM" component.
769 This property can be specified once only.
771Security:
772 :rfc:`7986` states that UID values MUST NOT include any data that
773 might identify a user, host, domain, or any other security- or
774 privacy-sensitive information. It is RECOMMENDED that calendar user
775 agents now generate "UID" values that are hex-encoded random
776 Universally Unique Identifier (UUID) values as defined in
777 Sections 4.4 and 4.5 of :rfc:`4122`.
778 You can use the :mod:`uuid` module to generate new UUIDs.
780Compatibility:
781 For Alarms, ``X-ALARMUID`` is also considered.
783Examples:
784 The following is an example of such a property value:
785 ``5FC53010-1267-4F8E-BC28-1D7AE55A7C99``.
787 Set the UID of a calendar:
789 .. code-block:: pycon
791 >>> from icalendar import Calendar
792 >>> from uuid import uuid4
793 >>> calendar = Calendar()
794 >>> calendar.uid = uuid4()
795 >>> print(calendar.to_ical())
796 BEGIN:VCALENDAR
797 UID:d755cef5-2311-46ed-a0e1-6733c9e15c63
798 END:VCALENDAR
800""",
801)
803summary_property = multi_language_text_property(
804 "SUMMARY",
805 None,
806 """SUMMARY defines a short summary or subject for the calendar component.
808Property Parameters:
809 IANA, non-standard, alternate text
810 representation, and language property parameters can be specified
811 on this property.
813Conformance:
814 The property can be specified in "VEVENT", "VTODO",
815 "VJOURNAL", or "VALARM" calendar components.
817Description:
818 This property is used in the "VEVENT", "VTODO", and
819 "VJOURNAL" calendar components to capture a short, one-line
820 summary about the activity or journal entry.
822 This property is used in the "VALARM" calendar component to
823 capture the subject of an EMAIL category of alarm.
825Examples:
826 The following is an example of this property:
828 .. code-block:: pycon
830 SUMMARY:Department Party
831""",
832)
834description_property = multi_language_text_property(
835 "DESCRIPTION",
836 None,
837 """DESCRIPTION provides a more complete description of the calendar component than that provided by the "SUMMARY" property.
839Property Parameters:
840 IANA, non-standard, alternate text
841 representation, and language property parameters can be specified
842 on this property.
844Conformance:
845 The property can be specified in the "VEVENT", "VTODO",
846 "VJOURNAL", or "VALARM" calendar components. The property can be
847 specified multiple times only within a "VJOURNAL" calendar
848 component.
850Description:
851 This property is used in the "VEVENT" and "VTODO" to
852 capture lengthy textual descriptions associated with the activity.
854 This property is used in the "VALARM" calendar component to
855 capture the display text for a DISPLAY category of alarm, and to
856 capture the body text for an EMAIL category of alarm.
858Examples:
859 The following is an example of this property with formatted
860 line breaks in the property value:
862 .. code-block:: pycon
864 DESCRIPTION:Meeting to provide technical review for "Phoenix"
865 design.\\nHappy Face Conference Room. Phoenix design team
866 MUST attend this meeting.\\nRSVP to team leader.
868 """, # noqa: E501
869)
872def create_single_property(
873 prop: str,
874 value_attr: Optional[str],
875 value_type: tuple[type],
876 type_def: type,
877 doc: str,
878 vProp: type = vDDDTypes, # noqa: N803
879):
880 """Create a single property getter and setter.
882 :param prop: The name of the property.
883 :param value_attr: The name of the attribute to get the value from.
884 :param value_type: The type of the value.
885 :param type_def: The type of the property.
886 :param doc: The docstring of the property.
887 :param vProp: The type of the property from :mod:`icalendar.prop`.
888 """
890 def p_get(self: Component):
891 default = object()
892 result = self.get(prop, default)
893 if result is default:
894 return None
895 if isinstance(result, list):
896 raise InvalidCalendar(f"Multiple {prop} defined.")
897 value = result if value_attr is None else getattr(result, value_attr, result)
898 if not isinstance(value, value_type):
899 raise InvalidCalendar(
900 f"{prop} must be either a "
901 f"{' or '.join(t.__name__ for t in value_type)},"
902 f" not {value}."
903 )
904 return value
906 def p_set(self: Component, value) -> None:
907 if value is None:
908 p_del(self)
909 return
910 if not isinstance(value, value_type):
911 raise TypeError(
912 f"Use {' or '.join(t.__name__ for t in value_type)}, "
913 f"not {type(value).__name__}."
914 )
915 self[prop] = vProp(value)
916 if prop in self.exclusive:
917 for other_prop in self.exclusive:
918 if other_prop != prop:
919 self.pop(other_prop, None)
921 p_set.__annotations__["value"] = p_get.__annotations__["return"] = Optional[
922 type_def
923 ]
925 def p_del(self: Component):
926 self.pop(prop)
928 p_doc = f"""The {prop} property.
930 {doc}
932 Accepted values: {", ".join(t.__name__ for t in value_type)}.
933 If the attribute has invalid values, we raise InvalidCalendar.
934 If the value is absent, we return None.
935 You can also delete the value with del or by setting it to None.
936 """
937 return property(p_get, p_set, p_del, p_doc)
940X_MOZ_SNOOZE_TIME_property = single_utc_property(
941 "X-MOZ-SNOOZE-TIME", "Thunderbird: Alarms before this time are snoozed."
942)
943X_MOZ_LASTACK_property = single_utc_property(
944 "X-MOZ-LASTACK", "Thunderbird: Alarms before this time are acknowledged."
945)
948def property_get_duration(self: Component) -> Optional[timedelta]:
949 """Getter for property DURATION."""
950 default = object()
951 duration = self.get("duration", default)
952 if isinstance(duration, vDDDTypes):
953 return duration.dt
954 if isinstance(duration, vDuration):
955 return duration.td
956 if duration is not default and not isinstance(duration, timedelta):
957 raise InvalidCalendar(
958 f"DURATION must be a timedelta, not {type(duration).__name__}."
959 )
960 return None
963def property_set_duration(self: Component, value: Optional[timedelta]):
964 """Setter for property DURATION."""
965 if value is None:
966 self.pop("duration", None)
967 return
968 if not isinstance(value, timedelta):
969 raise TypeError(f"Use timedelta, not {type(value).__name__}.")
970 self["duration"] = vDuration(value)
971 self.pop("DTEND")
972 self.pop("DUE")
975def property_del_duration(self: Component):
976 """Delete property DURATION."""
977 self.pop("DURATION")
980property_doc_duration_template = """The DURATION property.
982The "DTSTART" property for a "{component}" specifies the inclusive
983start of the {component}.
984The "DURATION" property in conjunction with the DTSTART property
985for a "{component}" calendar component specifies the non-inclusive end
986of the event.
988If you would like to calculate the duration of a {component}, do not use this.
989Instead use the duration property (lower case).
990"""
993def duration_property(component: str) -> property:
994 """Return the duration property."""
995 return property(
996 property_get_duration,
997 property_set_duration,
998 property_del_duration,
999 property_doc_duration_template.format(component=component),
1000 )
1003def multi_text_property(name: str, docs: str) -> property:
1004 """Get a property that can occur several times and is text.
1006 Examples: Journal.descriptions, Event.comments
1007 """
1009 def fget(self: Component) -> list[str]:
1010 """Get the values."""
1011 descriptions = self.get(name)
1012 if descriptions is None:
1013 return []
1014 if not isinstance(descriptions, SEQUENCE_TYPES):
1015 return [descriptions]
1016 return descriptions
1018 def fset(self: Component, values: Optional[str | Sequence[str]]):
1019 """Set the values."""
1020 fdel(self)
1021 if values is None:
1022 return
1023 if isinstance(values, str):
1024 self.add(name, values)
1025 else:
1026 for description in values:
1027 self.add(name, description)
1029 def fdel(self: Component):
1030 """Delete the values."""
1031 self.pop(name)
1033 return property(fget, fset, fdel, docs)
1036descriptions_property = multi_text_property(
1037 "DESCRIPTION",
1038 """DESCRIPTION provides a more complete description of the calendar component than that provided by the "SUMMARY" property.
1040Property Parameters:
1041 IANA, non-standard, alternate text
1042 representation, and language property parameters can be specified
1043 on this property.
1045Conformance:
1046 The property can be
1047 specified multiple times only within a "VJOURNAL" calendar component.
1049Description:
1050 This property is used in the "VJOURNAL" calendar component to
1051 capture one or more textual journal entries.
1053Examples:
1054 The following is an example of this property with formatted
1055 line breaks in the property value:
1057 .. code-block:: pycon
1059 DESCRIPTION:Meeting to provide technical review for "Phoenix"
1060 design.\\nHappy Face Conference Room. Phoenix design team
1061 MUST attend this meeting.\\nRSVP to team leader.
1063""", # noqa: E501
1064)
1066comments_property = multi_text_property(
1067 "COMMENT",
1068 """COMMENT is used to specify a comment to the calendar user.
1070Purpose:
1071 This property specifies non-processing information intended
1072 to provide a comment to the calendar user.
1074Conformance:
1075 In :rfc:`5545`, this property can be specified multiple times in
1076 "VEVENT", "VTODO", "VJOURNAL", and "VFREEBUSY" calendar components
1077 as well as in the "STANDARD" and "DAYLIGHT" sub-components.
1078 In :rfc:`7953`, this property can be specified multiple times in
1079 "VAVAILABILITY" and "VAVAILABLE".
1081Property Parameters:
1082 IANA, non-standard, alternate text
1083 representation, and language property parameters can be specified
1084 on this property.
1086""",
1087)
1090def _get_organizer(self: Component) -> Optional[vCalAddress]:
1091 """ORGANIZER defines the organizer for a calendar component.
1093 Property Parameters:
1094 IANA, non-standard, language, common name,
1095 directory entry reference, and sent-by property parameters can be
1096 specified on this property.
1098 Conformance:
1099 This property MUST be specified in an iCalendar object
1100 that specifies a group-scheduled calendar entity. This property
1101 MUST be specified in an iCalendar object that specifies the
1102 publication of a calendar user's busy time. This property MUST
1103 NOT be specified in an iCalendar object that specifies only a time
1104 zone definition or that defines calendar components that are not
1105 group-scheduled components, but are components only on a single
1106 user's calendar.
1108 Description:
1109 This property is specified within the "VEVENT",
1110 "VTODO", and "VJOURNAL" calendar components to specify the
1111 organizer of a group-scheduled calendar entity. The property is
1112 specified within the "VFREEBUSY" calendar component to specify the
1113 calendar user requesting the free or busy time. When publishing a
1114 "VFREEBUSY" calendar component, the property is used to specify
1115 the calendar that the published busy time came from.
1117 The property has the property parameters "CN", for specifying the
1118 common or display name associated with the "Organizer", "DIR", for
1119 specifying a pointer to the directory information associated with
1120 the "Organizer", "SENT-BY", for specifying another calendar user
1121 that is acting on behalf of the "Organizer". The non-standard
1122 parameters may also be specified on this property. If the
1123 "LANGUAGE" property parameter is specified, the identified
1124 language applies to the "CN" parameter value.
1125 """
1126 return self.get("ORGANIZER")
1129def _set_organizer(self: Component, value: Optional[vCalAddress | str]):
1130 """Set the value."""
1131 _del_organizer(self)
1132 if value is not None:
1133 self.add("ORGANIZER", value)
1136def _del_organizer(self: Component):
1137 """Delete the value."""
1138 self.pop("ORGANIZER")
1141organizer_property = property(_get_organizer, _set_organizer, _del_organizer)
1144def single_string_enum_property(
1145 name: str, enum: type[StrEnum], default: StrEnum, docs: str
1146) -> property:
1147 """Create a property to access a single string value and convert it to an enum."""
1148 prop = single_string_property(name, docs, default=default)
1150 def fget(self: Component) -> StrEnum:
1151 """Get the value."""
1152 value = prop.fget(self)
1153 if value == default:
1154 return default
1155 return enum(str(value))
1157 def fset(self: Component, value: str | StrEnum | None) -> None:
1158 """Set the value."""
1159 if value == "":
1160 value = None
1161 prop.fset(self, value)
1163 return property(fget, fset, prop.fdel, doc=docs)
1166busy_type_property = single_string_enum_property(
1167 "BUSYTYPE",
1168 BUSYTYPE,
1169 BUSYTYPE.BUSY_UNAVAILABLE,
1170 """BUSYTYPE specifies the default busy time type.
1172Returns:
1173 :class:`icalendar.enums.BUSYTYPE`
1175Description:
1176 This property is used to specify the default busy time
1177 type. The values correspond to those used by the FBTYPE"
1178 parameter used on a "FREEBUSY" property, with the exception that
1179 the "FREE" value is not used in this property. If not specified
1180 on a component that allows this property, the default is "BUSY-
1181 UNAVAILABLE".
1182""",
1183)
1185priority_property = single_int_property(
1186 "PRIORITY",
1187 0,
1188 """
1190Conformance:
1191 This property can be specified in "VEVENT" and "VTODO" calendar components
1192 according to :rfc:`5545`.
1193 :rfc:`7953` adds this property to "VAVAILABILITY".
1195Description:
1196 This priority is specified as an integer in the range 0
1197 to 9. A value of 0 specifies an undefined priority. A value of 1
1198 is the highest priority. A value of 2 is the second highest
1199 priority. Subsequent numbers specify a decreasing ordinal
1200 priority. A value of 9 is the lowest priority.
1202 A CUA with a three-level priority scheme of "HIGH", "MEDIUM", and
1203 "LOW" is mapped into this property such that a property value in
1204 the range of 1 to 4 specifies "HIGH" priority. A value of 5 is
1205 the normal or "MEDIUM" priority. A value in the range of 6 to 9
1206 is "LOW" priority.
1208 A CUA with a priority schema of "A1", "A2", "A3", "B1", "B2", ...,
1209 "C3" is mapped into this property such that a property value of 1
1210 specifies "A1", a property value of 2 specifies "A2", a property
1211 value of 3 specifies "A3", and so forth up to a property value of
1212 9 specifies "C3".
1214 Other integer values are reserved for future use.
1216 Within a "VEVENT" calendar component, this property specifies a
1217 priority for the event. This property may be useful when more
1218 than one event is scheduled for a given time period.
1220 Within a "VTODO" calendar component, this property specified a
1221 priority for the to-do. This property is useful in prioritizing
1222 multiple action items for a given time period.
1223""",
1224)
1226class_property = single_string_enum_property(
1227 "CLASS",
1228 CLASS,
1229 CLASS.PUBLIC,
1230 """CLASS specifies the class of the calendar component.
1232Returns:
1233 :class:`icalendar.enums.CLASS`
1235Description:
1236 An access classification is only one component of the
1237 general security system within a calendar application. It
1238 provides a method of capturing the scope of the access the
1239 calendar owner intends for information within an individual
1240 calendar entry. The access classification of an individual
1241 iCalendar component is useful when measured along with the other
1242 security components of a calendar system (e.g., calendar user
1243 authentication, authorization, access rights, access role, etc.).
1244 Hence, the semantics of the individual access classifications
1245 cannot be completely defined by this memo alone. Additionally,
1246 due to the "blind" nature of most exchange processes using this
1247 memo, these access classifications cannot serve as an enforcement
1248 statement for a system receiving an iCalendar object. Rather,
1249 they provide a method for capturing the intention of the calendar
1250 owner for the access to the calendar component. If not specified
1251 in a component that allows this property, the default value is
1252 PUBLIC. Applications MUST treat x-name and iana-token values they
1253 don't recognize the same way as they would the PRIVATE value.
1254""",
1255)
1257transparency_property = single_string_enum_property(
1258 "TRANSP",
1259 TRANSP,
1260 TRANSP.OPAQUE,
1261 """TRANSP defines whether or not an event is transparent to busy time searches.
1263Returns:
1264 :class:`icalendar.enums.TRANSP`
1266Description:
1267 Time Transparency is the characteristic of an event
1268 that determines whether it appears to consume time on a calendar.
1269 Events that consume actual time for the individual or resource
1270 associated with the calendar SHOULD be recorded as OPAQUE,
1271 allowing them to be detected by free/busy time searches. Other
1272 events, which do not take up the individual's (or resource's) time
1273 SHOULD be recorded as TRANSPARENT, making them invisible to free/
1274 busy time searches.
1275""",
1276)
1277status_property = single_string_enum_property(
1278 "STATUS",
1279 STATUS,
1280 "",
1281 """STATUS defines the overall status or confirmation for the calendar component.
1283Returns:
1284 :class:`icalendar.enums.STATUS`
1286The default value is ``""``.
1288Description:
1289 In a group-scheduled calendar component, the property
1290 is used by the "Organizer" to provide a confirmation of the event
1291 to the "Attendees". For example in a "VEVENT" calendar component,
1292 the "Organizer" can indicate that a meeting is tentative,
1293 confirmed, or cancelled. In a "VTODO" calendar component, the
1294 "Organizer" can indicate that an action item needs action, is
1295 completed, is in process or being worked on, or has been
1296 cancelled. In a "VJOURNAL" calendar component, the "Organizer"
1297 can indicate that a journal entry is draft, final, or has been
1298 cancelled or removed.
1299""",
1300)
1302url_property = single_string_property(
1303 "URL",
1304 """A Uniform Resource Locator (URL) associated with the iCalendar object.
1306Description:
1307 This property may be used in a calendar component to
1308 convey a location where a more dynamic rendition of the calendar
1309 information associated with the calendar component can be found.
1310 This memo does not attempt to standardize the form of the URI, nor
1311 the format of the resource pointed to by the property value. If
1312 the URL property and Content-Location MIME header are both
1313 specified, they MUST point to the same resource.
1314""",
1315)
1317location_property = multi_language_text_property(
1318 "LOCATION",
1319 None,
1320 """The intended venue for the activity defined by a calendar component.
1322Property Parameters:
1323 IANA, non-standard, alternate text
1324 representation, and language property parameters can be specified
1325 on this property.
1327Conformance:
1328 Since :rfc:`5545`, this property can be specified in "VEVENT" or "VTODO"
1329 calendar component.
1330 :rfc:`7953` adds this property to "VAVAILABILITY" and "VAVAILABLE".
1332Description:
1333 Specific venues such as conference or meeting rooms may
1334 be explicitly specified using this property. An alternate
1335 representation may be specified that is a URI that points to
1336 directory information with more structured specification of the
1337 location. For example, the alternate representation may specify
1338 either an LDAP URL :rfc:`4516` pointing to an LDAP server entry or a
1339 CID URL :rfc:`2392` pointing to a MIME body part containing a
1340 Virtual-Information Card (vCard) :rfc:`2426` for the location.
1342""",
1343)
1345contacts_property = multi_text_property(
1346 "CONTACT",
1347 """Contact information associated with the calendar component.
1349Purpose:
1350 This property is used to represent contact information or
1351 alternately a reference to contact information associated with the
1352 calendar component.
1354Property Parameters:
1355 IANA, non-standard, alternate text
1356 representation, and language property parameters can be specified
1357 on this property.
1359Conformance:
1360 In :rfc:`5545`, this property can be specified in a "VEVENT", "VTODO",
1361 "VJOURNAL", or "VFREEBUSY" calendar component.
1362 In :rfc:`7953`, this property can be specified in a "VAVAILABILITY"
1363 amd "VAVAILABLE" calendar component.
1365Description:
1366 The property value consists of textual contact
1367 information. An alternative representation for the property value
1368 can also be specified that refers to a URI pointing to an
1369 alternate form, such as a vCard :rfc:`2426`, for the contact
1370 information.
1372Example:
1373 The following is an example of this property referencing
1374 textual contact information:
1376 .. code-block:: text
1378 CONTACT:Jim Dolittle\\, ABC Industries\\, +1-919-555-1234
1380 The following is an example of this property with an alternate
1381 representation of an LDAP URI to a directory entry containing the
1382 contact information:
1384 .. code-block:: text
1386 CONTACT;ALTREP="ldap://example.com:6666/o=ABC%20Industries\\,
1387 c=US???(cn=Jim%20Dolittle)":Jim Dolittle\\, ABC Industries\\,
1388 +1-919-555-1234
1390 The following is an example of this property with an alternate
1391 representation of a MIME body part containing the contact
1392 information, such as a vCard :rfc:`2426` embedded in a text/
1393 directory media type :rfc:`2425`:
1395 .. code-block:: text
1397 CONTACT;ALTREP="CID:part3.msg970930T083000SILVER@example.com":
1398 Jim Dolittle\\, ABC Industries\\, +1-919-555-1234
1400 The following is an example of this property referencing a network
1401 resource, such as a vCard :rfc:`2426` object containing the contact
1402 information:
1404 .. code-block:: text
1406 CONTACT;ALTREP="http://example.com/pdi/jdoe.vcf":Jim
1407 Dolittle\\, ABC Industries\\, +1-919-555-1234
1408""",
1409)
1412def timezone_datetime_property(name: str, docs: str):
1413 """Create a property to access the values with a proper timezone."""
1415 return single_utc_property(name, docs)
1418rfc_7953_dtstart_property = timezone_datetime_property(
1419 "DTSTART",
1420 """Start of the component.
1422 This is almost the same as :attr:`Event.DTSTART` with one exception:
1423 The values MUST have a timezone and DATE is not allowed.
1425 Description:
1426 :rfc:`7953`: If specified, the "DTSTART" and "DTEND" properties in
1427 "VAVAILABILITY" components and "AVAILABLE" subcomponents MUST be
1428 "DATE-TIME" values specified as either the date with UTC time or
1429 the date with local time and a time zone reference.
1431 """,
1432)
1434rfc_7953_dtend_property = timezone_datetime_property(
1435 "DTEND",
1436 """Start of the component.
1438 This is almost the same as :attr:`Event.DTEND` with one exception:
1439 The values MUST have a timezone and DATE is not allowed.
1441 Description:
1442 :rfc:`7953`: If specified, the "DTSTART" and "DTEND" properties in
1443 "VAVAILABILITY" components and "AVAILABLE" subcomponents MUST be
1444 "DATE-TIME" values specified as either the date with UTC time or
1445 the date with local time and a time zone reference.
1446 """,
1447)
1450@property
1451def rfc_7953_duration_property(self) -> Optional[timedelta]:
1452 """Compute the duration of this component.
1454 If there is no :attr:`DTEND` or :attr:`DURATION` set, this is None.
1455 Otherwise, the duration is calculated from :attr:`DTSTART` and
1456 :attr:`DTEND`/:attr:`DURATION`.
1458 This is in accordance with :rfc:`7953`:
1459 If "DTEND" or "DURATION" are not present, then the end time is unbounded.
1460 """
1461 duration = self.DURATION
1462 if duration:
1463 return duration
1464 end = self.DTEND
1465 if end is None:
1466 return None
1467 start = self.DTSTART
1468 if start is None:
1469 raise IncompleteComponent("Cannot compute duration without start.")
1470 return end - start
1473@property
1474def rfc_7953_end_property(self) -> Optional[timedelta]:
1475 """Compute the duration of this component.
1477 If there is no :attr:`DTEND` or :attr:`DURATION` set, this is None.
1478 Otherwise, the duration is calculated from :attr:`DTSTART` and
1479 :attr:`DTEND`/:attr:`DURATION`.
1481 This is in accordance with :rfc:`7953`:
1482 If "DTEND" or "DURATION" are not present, then the end time is unbounded.
1483 """
1484 duration = self.DURATION
1485 if duration:
1486 start = self.DTSTART
1487 if start is None:
1488 raise IncompleteComponent("Cannot compute end without start.")
1489 return start + duration
1490 end = self.DTEND
1491 if end is None:
1492 return None
1493 return end
1496@rfc_7953_end_property.setter
1497def rfc_7953_end_property(self, value: datetime):
1498 self.DTEND = value
1501@rfc_7953_end_property.deleter
1502def rfc_7953_end_property(self):
1503 del self.DTEND
1506__all__ = [
1507 "attendees_property",
1508 "busy_type_property",
1509 "categories_property",
1510 "class_property",
1511 "color_property",
1512 "comments_property",
1513 "contacts_property",
1514 "create_single_property",
1515 "description_property",
1516 "descriptions_property",
1517 "duration_property",
1518 "exdates_property",
1519 "location_property",
1520 "multi_language_text_property",
1521 "organizer_property",
1522 "priority_property",
1523 "property_del_duration",
1524 "property_doc_duration_template",
1525 "property_get_duration",
1526 "property_set_duration",
1527 "rdates_property",
1528 "rfc_7953_dtend_property",
1529 "rfc_7953_dtstart_property",
1530 "rfc_7953_duration_property",
1531 "rfc_7953_end_property",
1532 "rrules_property",
1533 "sequence_property",
1534 "single_int_property",
1535 "single_utc_property",
1536 "status_property",
1537 "summary_property",
1538 "transparency_property",
1539 "uid_property",
1540 "url_property",
1541]