Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/cal/alarm.py: 38%
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""":rfc:`5545` VALARM component."""
3from __future__ import annotations
5from datetime import date, datetime, timedelta
6from typing import TYPE_CHECKING, NamedTuple
8from icalendar.attr import (
9 CONCEPTS_TYPE_SETTER,
10 LINKS_TYPE_SETTER,
11 RELATED_TO_TYPE_SETTER,
12 attendees_property,
13 create_single_property,
14 description_property,
15 property_del_duration,
16 property_get_duration,
17 property_set_duration,
18 repeat_property,
19 single_int_property,
20 single_string_property,
21 single_utc_property,
22 summary_property,
23 uid_property,
24)
25from icalendar.cal.component import Component
26from icalendar.cal.examples import get_example
27from icalendar.error import InvalidCalendar
28from icalendar.prop.binary import vBinary
30if TYPE_CHECKING:
31 import uuid
32 from collections.abc import Sequence
34 from icalendar.prop import vCalAddress
37class Alarm(Component):
38 """
39 A "VALARM" calendar component is a grouping of component
40 properties that defines an alarm or reminder for an event or a
41 to-do. For example, it may be used to define a reminder for a
42 pending event or an overdue to-do.
44 Example:
46 The following example creates an alarm which uses an audio file
47 from an FTP server.
49 .. code-block:: pycon
51 >>> from icalendar import Alarm
52 >>> alarm = Alarm.example()
53 >>> print(alarm.to_ical().decode())
54 BEGIN:VALARM
55 ACTION:AUDIO
56 ATTACH;FMTTYPE=audio/basic:ftp://example.com/pub/sounds/bell-01.aud
57 DURATION:PT15M
58 REPEAT:4
59 TRIGGER;VALUE=DATE-TIME:19970317T133000Z
60 END:VALARM
61 """
63 name = "VALARM"
64 # some properties MAY/MUST/MUST NOT appear depending on ACTION value
65 required = (
66 "ACTION",
67 "TRIGGER",
68 )
69 singletons = (
70 "ACTION",
71 "DESCRIPTION",
72 "SUMMARY",
73 "TRIGGER",
74 "DURATION",
75 "REPEAT",
76 "UID",
77 "PROXIMITY",
78 "ACKNOWLEDGED",
79 )
80 inclusive = (
81 (
82 "DURATION",
83 "REPEAT",
84 ),
85 (
86 "SUMMARY",
87 "ATTENDEE",
88 ),
89 )
90 multiple = ("ATTENDEE", "ATTACH", "RELATED-TO")
92 REPEAT = single_int_property(
93 "REPEAT",
94 0,
95 """The number of additional times the alarm is triggered after the initial trigger.
97 Defaults to ``0``, meaning the alarm fires once. To repeat the alarm,
98 set both :attr:`REPEAT` and :attr:`DURATION`. The :attr:`DURATION`
99 sets the gap between repetitions. :attr:`REPEAT` is the count of *additional*
100 triggers, so a :attr:`REPEAT` of ``2`` produces three alarms in total
101 (the initial trigger plus two repeats).
103 Conforming with :rfc:`5545#section-3.8.6.2`, this property can appear
104 once in an :class:`~icalendar.cal.alarm.Alarm` component and must be
105 paired with :attr:`DURATION`.
107 Example:
108 Build an alarm that fires once and then repeats twice at
109 five-minute intervals.
111 .. code-block:: pycon
113 >>> from datetime import timedelta
114 >>> from icalendar import Alarm
115 >>> alarm = Alarm()
116 >>> alarm.TRIGGER = timedelta(minutes=-15)
117 >>> alarm.DURATION = timedelta(minutes=5)
118 >>> alarm.REPEAT = 2
119 >>> alarm.REPEAT
120 2
121 """,
122 )
124 DURATION = property(
125 property_get_duration,
126 property_set_duration,
127 property_del_duration,
128 """The delay between repeated triggers of a repeating alarm.
130 Returns a :class:`datetime.timedelta` or ``None`` when the alarm
131 has no :attr:`DURATION` set. Setting this attribute accepts a
132 :class:`~datetime.timedelta`; deleting it removes the property
133 from the component.
135 :attr:`DURATION` is meaningful only for repeating alarms and must
136 be paired with :attr:`REPEAT`. The two together produce
137 :attr:`REPEAT` additional triggers, each spaced by :attr:`DURATION` after
138 the initial trigger.
140 Conforming with :rfc:`5545#section-3.8.2.5`, the :attr:`DURATION` property
141 can appear once in an :class:`~icalendar.cal.alarm.Alarm` component.
143 Example:
144 Pair :attr:`DURATION` with :attr:`REPEAT` to produce three
145 triggers spaced ten minutes apart.
147 .. code-block:: pycon
149 >>> from datetime import timedelta
150 >>> from icalendar import Alarm
151 >>> alarm = Alarm()
152 >>> alarm.TRIGGER = timedelta(minutes=-30)
153 >>> alarm.DURATION = timedelta(minutes=10)
154 >>> alarm.REPEAT = 2
155 >>> alarm.DURATION
156 datetime.timedelta(seconds=600)
157 """,
158 )
160 ACKNOWLEDGED = single_utc_property(
161 "ACKNOWLEDGED",
162 """This property is the UTC datetime at which this alarm was last sent or acknowledged as defined in :rfc:`9074`.
164 Setting this property allows calendar clients to
165 dismiss or suppress an alarm across multiple devices. Once set to a value
166 greater than or equal to the alarm's computed trigger time, conforming clients
167 will not refire the alarm.
169 Returns ``None`` when no acknowledgment has been recorded.
171 Example:
172 Mark an alarm as acknowledged. Note that the example uses an arbitrary time
173 for the purpose of passing doctests. In actual practice, clients should
174 use the current time in UTC, such as ``datetime.now(UTC)``.
176 .. code-block:: pycon
178 >>> from datetime import timezone, datetime
179 >>> from icalendar import Alarm
180 >>> UTC = timezone.utc
181 >>> alarm = Alarm()
182 >>> alarm.ACKNOWLEDGED = datetime(2024, 1, 15, 10, 0, tzinfo=UTC)
183 >>> alarm.ACKNOWLEDGED
184 datetime.datetime(2024, 1, 15, 10, 0, tzinfo=ZoneInfo(key='UTC'))
186 See also:
187 :attr:`TRIGGER`, the time at which the alarm fires.
188 """,
189 )
191 TRIGGER = create_single_property(
192 "TRIGGER",
193 "dt",
194 (datetime, timedelta),
195 timedelta | datetime | None,
196 """The time at which this alarm fires, per :rfc:`5545#section-3.8.6.3`.
198 The value is either a :class:`~datetime.timedelta` (relative trigger) or a
199 UTC :class:`~datetime.datetime` (absolute trigger).
201 A negative :class:`~datetime.timedelta` fires *before* the related
202 component boundary (start or end); a positive one fires *after* it.
203 Use :attr:`TRIGGER_RELATED` to choose whether the offset is measured from
204 the start or the end of the parent event or to-do.
205 An absolute trigger fires at an exact UTC point in time regardless of the
206 parent component's dates.
208 Examples:
209 Set an alarm to fire 15 minutes before the start of an event.
211 .. code-block:: pycon
213 >>> from datetime import datetime, timedelta, timezone
214 >>> from icalendar import Alarm, Event
215 >>> UTC = timezone.utc
216 >>> event = Event()
217 >>> event.start = datetime(2024, 1, 15, 10, 0, tzinfo=UTC)
218 >>> alarm = Alarm()
219 >>> alarm.TRIGGER = timedelta(minutes=-15)
220 >>> event.add_component(alarm)
221 >>> event.alarms.times[0].trigger
222 datetime.datetime(2024, 1, 15, 9, 45, tzinfo=datetime.timezone.utc)
224 Set an absolute trigger to fire at a specific UTC time.
226 .. code-block:: pycon
228 >>> absolute_alarm = Alarm()
229 >>> absolute_alarm.TRIGGER = datetime(2024, 1, 15, 9, 45, tzinfo=UTC)
230 >>> absolute_alarm.TRIGGER
231 datetime.datetime(2024, 1, 15, 9, 45, tzinfo=datetime.timezone.utc)
233 See also:
234 :attr:`TRIGGER_RELATED`, :attr:`DURATION`, :attr:`REPEAT`
235 """,
236 )
238 @property
239 def TRIGGER_RELATED(self) -> str:
240 """The RELATED parameter of the TRIGGER property.
242 Values are either "START" (default) or "END".
244 A value of START will set the alarm to trigger off the
245 start of the associated event or to-do. A value of END will set
246 the alarm to trigger off the end of the associated event or to-do.
248 In this example, we create an alarm that triggers two hours after the
249 end of its parent component.
251 >>> from icalendar import Alarm
252 >>> from datetime import timedelta
253 >>> alarm = Alarm()
254 >>> alarm.TRIGGER = timedelta(hours=2)
255 >>> alarm.TRIGGER_RELATED = "END"
256 """
257 trigger = self.get("TRIGGER")
258 if trigger is None:
259 return "START"
260 return trigger.params.get("RELATED", "START")
262 @TRIGGER_RELATED.setter
263 def TRIGGER_RELATED(self, value: str):
264 """Set "START" or "END"."""
265 trigger = self.get("TRIGGER")
266 if trigger is None:
267 raise ValueError(
268 "You must set a TRIGGER before setting the RELATED parameter."
269 )
270 trigger.params["RELATED"] = value
272 class Triggers(NamedTuple):
273 """The computed times of alarm triggers.
275 start - triggers relative to the start of the Event or Todo (timedelta)
277 end - triggers relative to the end of the Event or Todo (timedelta)
279 absolute - triggers at a datetime in UTC
280 """
282 start: tuple[timedelta]
283 end: tuple[timedelta]
284 absolute: tuple[datetime]
286 @property
287 def triggers(self):
288 """The computed triggers of an Alarm.
290 This takes the TRIGGER, DURATION and REPEAT properties into account.
292 Here, we create an alarm that triggers 3 times before the start of the
293 parent component.
295 >>> from icalendar import Alarm
296 >>> from datetime import timedelta
297 >>> alarm = Alarm()
298 >>> alarm.TRIGGER = timedelta(hours=-4) # trigger 4 hours before START
299 >>> alarm.DURATION = timedelta(hours=1) # after 1 hour trigger again
300 >>> alarm.REPEAT = 2 # trigger 2 more times
301 >>> alarm.triggers.start == (timedelta(hours=-4), timedelta(hours=-3), timedelta(hours=-2))
302 True
303 >>> alarm.triggers.end
304 ()
305 >>> alarm.triggers.absolute
306 ()
307 """
308 start = []
309 end = []
310 absolute = []
311 trigger = self.TRIGGER
312 if trigger is not None:
313 if isinstance(trigger, date):
314 absolute.append(trigger)
315 add = absolute
316 elif self.TRIGGER_RELATED == "START":
317 start.append(trigger)
318 add = start
319 else:
320 end.append(trigger)
321 add = end
322 duration = self.DURATION
323 if duration is not None:
324 for _ in range(self.repeat):
325 add.append(add[-1] + duration)
326 return self.Triggers(
327 start=tuple(start), end=tuple(end), absolute=tuple(absolute)
328 )
330 repeat = repeat_property
332 ACTION = single_string_property(
333 "ACTION",
334 """The action invoked when the alarm triggers.
336 Typical values defined by :rfc:`5545#section-3.8.6.1` are
337 ``AUDIO``, ``DISPLAY``, and ``EMAIL``. The empty string is
338 returned when no ``ACTION`` property is present.
339 """,
340 )
341 uid = single_string_property(
342 "UID",
343 uid_property.__doc__,
344 ["X-ALARMUID", "X-EVOLUTION-ALARM-UID"],
345 )
346 summary = summary_property
347 description = description_property
348 attendees = attendees_property
350 @classmethod
351 def new(
352 cls,
353 /,
354 attendees: list[vCalAddress] | None = None,
355 concepts: CONCEPTS_TYPE_SETTER = None,
356 description: str | None = None,
357 links: LINKS_TYPE_SETTER = None,
358 refids: list[str] | str | None = None,
359 related_to: RELATED_TO_TYPE_SETTER = None,
360 summary: str | None = None,
361 uid: str | uuid.UUID | None = None,
362 ):
363 """Create a new alarm with all required properties.
365 This creates a new Alarm in accordance with :rfc:`5545`.
367 Parameters:
368 attendees: The :attr:`attendees` of the alarm.
369 concepts: The :attr:`~icalendar.cal.component.Component.concepts` of the alarm.
370 description: The :attr:`description` of the alarm.
371 links: The :attr:`~icalendar.cal.component.Component.links` of the alarm.
372 refids: :attr:`~icalendar.cal.component.Component.refids` of the alarm.
373 related_to: :attr:`~icalendar.cal.component.Component.related_to` of the alarm.
374 summary: The :attr:`summary` of the alarm.
375 uid: The :attr:`uid` of the alarm.
377 Returns:
378 :class:`Alarm`
380 Raises:
381 ~error.InvalidCalendar: If the content is not valid
382 according to :rfc:`5545`.
384 .. warning:: As time progresses, we will be stricter with the validation.
385 """
386 alarm: Alarm = super().new(
387 links=links,
388 related_to=related_to,
389 refids=refids,
390 concepts=concepts,
391 )
392 alarm.summary = summary
393 alarm.description = description
394 alarm.uid = uid
395 alarm.attendees = attendees
396 return alarm
398 def _apply_duration_repeat(
399 self,
400 duration: timedelta | None,
401 repeat: int | None,
402 ) -> None:
403 if duration is not None or repeat is not None:
404 if duration is None or repeat is None:
405 raise InvalidCalendar(
406 "DURATION and REPEAT must be set together or not at all"
407 )
408 self.DURATION = duration
409 self.REPEAT = repeat
411 @classmethod
412 def new_display(
413 cls,
414 description: str,
415 trigger: timedelta | datetime,
416 duration: timedelta | None = None,
417 repeat: int | None = None,
418 uid: str | uuid.UUID | None = None,
419 links: LINKS_TYPE_SETTER = None,
420 related_to: RELATED_TO_TYPE_SETTER = None,
421 refids: list[str] | str | None = None,
422 concepts: CONCEPTS_TYPE_SETTER = None,
423 ) -> Alarm:
424 """Create a new DISPLAY alarm that shows a text reminder.
426 A DISPLAY alarm pops up a text notification at the trigger time.
427 This is the most common alarm type used by calendar clients.
429 Conforms to :rfc:`5545#section-3.6.6`.
431 Parameters:
432 description: Required. The text to display when the alarm fires.
433 Corresponds to the :attr:`description` property.
434 trigger: Required. When the alarm fires, as a :class:`~datetime.timedelta`
435 relative to the event start (negative means before) or as an
436 absolute :class:`~datetime.datetime` (recommend UTC-aware).
437 concepts: The :attr:`~icalendar.cal.component.Component.concepts` of the alarm.
438 duration: Gap between repeated triggers. Must be paired with
439 ``repeat``. Corresponds to the :attr:`DURATION` property.
440 links: The :attr:`~icalendar.cal.component.Component.links` of the alarm.
441 refids: The :attr:`~icalendar.cal.component.Component.refids` of the alarm.
442 related_to: The :attr:`~icalendar.cal.component.Component.related_to` of the alarm.
443 repeat: Number of *additional* times to fire after the initial
444 trigger. Must be paired with ``duration``.
445 Corresponds to the :attr:`REPEAT` property.
446 uid: Unique identifier for the alarm or ``None``.
448 Returns:
449 :class:`Alarm` with ``ACTION:DISPLAY`` set.
451 Raises:
452 ~icalendar.error.InvalidCalendar: If required fields are missing
453 or ``duration`` and ``repeat`` are not both provided together.
455 Example:
456 Create a display alarm that fires 15 minutes before the event:
458 .. code-block:: pycon
460 >>> from datetime import timedelta
461 >>> from icalendar import Alarm
462 >>> alarm = Alarm.new_display(
463 ... description="Team meeting in 15 minutes",
464 ... trigger=timedelta(minutes=-15),
465 ... )
466 >>> print(alarm.to_ical().decode())
467 BEGIN:VALARM
468 ACTION:DISPLAY
469 DESCRIPTION:Team meeting in 15 minutes
470 TRIGGER:-PT15M
471 END:VALARM
473 Attach the alarm to an event:
475 .. code-block:: python
477 from datetime import datetime, timedelta, timezone
478 from icalendar import Alarm, Event
480 event = Event.new(
481 summary="Team meeting",
482 start=datetime(2025, 6, 1, 10, 0, tzinfo=timezone.utc),
483 end=datetime(2025, 6, 1, 11, 0, tzinfo=timezone.utc),
484 )
485 event.add_component(Alarm.new_display(
486 description="Team meeting in 15 minutes",
487 trigger=timedelta(minutes=-15),
488 ))
489 """
490 if not description:
491 raise InvalidCalendar("DISPLAY alarm requires a description")
492 if trigger is None:
493 raise InvalidCalendar("DISPLAY alarm requires a trigger")
494 alarm: Alarm = cls.new(
495 description=description,
496 uid=uid,
497 links=links,
498 related_to=related_to,
499 refids=refids,
500 concepts=concepts,
501 )
502 alarm.add("ACTION", "DISPLAY")
503 alarm.TRIGGER = trigger
504 alarm._apply_duration_repeat(duration, repeat)
505 return alarm
507 @classmethod
508 def new_audio(
509 cls,
510 trigger: timedelta | datetime,
511 attach: str | bytes | None = None,
512 duration: timedelta | None = None,
513 repeat: int | None = None,
514 uid: str | uuid.UUID | None = None,
515 links: LINKS_TYPE_SETTER = None,
516 related_to: RELATED_TO_TYPE_SETTER = None,
517 refids: list[str] | str | None = None,
518 concepts: CONCEPTS_TYPE_SETTER = None,
519 ) -> Alarm:
520 """Create a new AUDIO alarm that plays a sound.
522 An AUDIO alarm plays a sound at the trigger time. An optional
523 ``attach`` URI points to the audio file to play; when omitted,
524 the client uses its default alert sound.
526 Conforms to :rfc:`5545#section-3.6.6`.
528 Parameters:
529 trigger: Required. When the alarm fires, as a :class:`~datetime.timedelta`
530 relative to the event start (negative means before) or as an
531 absolute :class:`~datetime.datetime` (recommend UTC-aware).
532 attach: Optional audio attachment. Pass a URI string such as
533 ``"ftp://example.com/pub/sounds/bell.aud"`` for a linked
534 sound file, or :class:`bytes` for inline binary audio data
535 (stored as ``VALUE=BINARY``). When ``None`` the client uses
536 its default sound.
537 concepts: The :attr:`~icalendar.cal.component.Component.concepts` of the alarm.
538 duration: Gap between repeated triggers. Must be paired with
539 ``repeat``. Corresponds to the :attr:`DURATION` property.
540 links: The :attr:`~icalendar.cal.component.Component.links` of the alarm.
541 refids: The :attr:`~icalendar.cal.component.Component.refids` of the alarm.
542 related_to: The :attr:`~icalendar.cal.component.Component.related_to` of the alarm.
543 repeat: Number of *additional* times to fire after the initial
544 trigger. Must be paired with ``duration``.
545 Corresponds to the :attr:`REPEAT` property.
546 uid: Unique identifier for the alarm or ``None``.
548 Returns:
549 :class:`Alarm` with ``ACTION:AUDIO`` set.
551 Raises:
552 ~icalendar.error.InvalidCalendar: If required fields are missing
553 or ``duration`` and ``repeat`` are not both provided together.
555 Example:
556 Create an audio alarm using a custom sound file:
558 .. code-block:: pycon
560 >>> from datetime import timedelta
561 >>> from icalendar import Alarm
562 >>> alarm = Alarm.new_audio(
563 ... trigger=timedelta(minutes=-5),
564 ... attach="ftp://example.com/pub/sounds/bell-01.aud",
565 ... )
566 >>> print(alarm.to_ical().decode())
567 BEGIN:VALARM
568 ACTION:AUDIO
569 ATTACH:ftp://example.com/pub/sounds/bell-01.aud
570 TRIGGER:-PT5M
571 END:VALARM
572 """
573 if trigger is None:
574 raise InvalidCalendar("AUDIO alarm requires a trigger")
575 alarm: Alarm = cls.new(
576 uid=uid,
577 links=links,
578 related_to=related_to,
579 refids=refids,
580 concepts=concepts,
581 )
582 alarm.add("ACTION", "AUDIO")
583 alarm.TRIGGER = trigger
584 if attach:
585 alarm.add(
586 "ATTACH", vBinary(attach) if isinstance(attach, bytes) else attach
587 )
588 alarm._apply_duration_repeat(duration, repeat)
589 return alarm
591 @classmethod
592 def new_email(
593 cls,
594 summary: str,
595 description: str,
596 trigger: timedelta | datetime,
597 attendees: Sequence[vCalAddress] | vCalAddress,
598 attachments: Sequence[str] | str | None = None,
599 duration: timedelta | None = None,
600 repeat: int | None = None,
601 uid: str | uuid.UUID | None = None,
602 links: LINKS_TYPE_SETTER = None,
603 related_to: RELATED_TO_TYPE_SETTER = None,
604 refids: list[str] | str | None = None,
605 concepts: CONCEPTS_TYPE_SETTER = None,
606 ) -> Alarm:
607 """Create a new EMAIL alarm that sends an email notification.
609 An EMAIL alarm sends an email to each address in ``attendees`` when
610 the alarm fires.
612 Conforms to :rfc:`5545#section-3.6.6`.
614 Parameters:
615 attendees: Required. One or more recipient addresses as
616 :class:`~icalendar.prop.cal_address.vCalAddress` instances. A
617 single address or a sequence of addresses. At least one is
618 required.
619 description: Required. Body of the email.
620 Corresponds to the :attr:`description` property.
621 summary: Required. Subject line of the email.
622 Corresponds to the :attr:`summary` property.
623 trigger: Required. When the alarm fires, as a :class:`~datetime.timedelta`
624 relative to the event start (negative means before) or as an
625 absolute :class:`~datetime.datetime` (recommend UTC-aware).
626 attachments: Optional URI or sequence of URIs to attach to the
627 email.
628 concepts: The :attr:`~icalendar.cal.component.Component.concepts` of the alarm.
629 duration: Gap between repeated triggers. Must be paired with
630 ``repeat``. Corresponds to the :attr:`DURATION` property.
631 links: The :attr:`~icalendar.cal.component.Component.links` of the alarm.
632 refids: The :attr:`~icalendar.cal.component.Component.refids` of the alarm.
633 related_to: The :attr:`~icalendar.cal.component.Component.related_to` of the alarm.
634 repeat: Number of *additional* times to fire after the initial
635 trigger. Must be paired with ``duration``.
636 Corresponds to the :attr:`REPEAT` property.
637 uid: Unique identifier for the alarm or ``None``.
639 Returns:
640 :class:`Alarm` with ``ACTION:EMAIL`` set.
642 Raises:
643 ~icalendar.error.InvalidCalendar: If required fields are missing,
644 ``attendees`` is empty, or ``duration`` and ``repeat`` are not
645 both provided together.
647 Example:
648 Create an email alarm sent to two recipients:
650 .. code-block:: pycon
652 >>> from datetime import timedelta
653 >>> from icalendar import Alarm, vCalAddress
654 >>> alarm = Alarm.new_email(
655 ... summary="Meeting reminder",
656 ... description="Your meeting starts in 30 minutes.",
657 ... trigger=timedelta(minutes=-30),
658 ... attendees=[vCalAddress("mailto:user@example.com")],
659 ... )
660 >>> print(alarm.to_ical().decode())
661 BEGIN:VALARM
662 ACTION:EMAIL
663 ATTENDEE:mailto:user@example.com
664 DESCRIPTION:Your meeting starts in 30 minutes.
665 SUMMARY:Meeting reminder
666 TRIGGER:-PT30M
667 END:VALARM
668 """
669 if isinstance(attendees, str):
670 attendees = [attendees]
671 if isinstance(attachments, str):
672 attachments = [attachments]
673 if not summary:
674 raise InvalidCalendar("EMAIL alarm requires a summary")
675 if not description:
676 raise InvalidCalendar("EMAIL alarm requires a description")
677 if trigger is None:
678 raise InvalidCalendar("EMAIL alarm requires a trigger")
679 if not attendees:
680 raise InvalidCalendar("EMAIL alarm requires at least one attendee")
681 alarm: Alarm = cls.new(
682 summary=summary,
683 description=description,
684 uid=uid,
685 attendees=attendees,
686 links=links,
687 related_to=related_to,
688 refids=refids,
689 concepts=concepts,
690 )
691 alarm.add("ACTION", "EMAIL")
692 alarm.TRIGGER = trigger
693 if attachments:
694 for attachment in attachments:
695 alarm.add("ATTACH", attachment)
696 alarm._apply_duration_repeat(duration, repeat)
697 return alarm
699 @classmethod
700 def example(cls, name: str = "example") -> Alarm:
701 """Return the alarm example with the given name."""
702 return cls.from_ical(get_example("alarms", name))
705__all__ = ["Alarm"]