Skip to content

All Properties

All Properties are extending the Property class. Let's first start with the base class and then list all the other properties.

Property

Bases: ICalBaseClass

This is the base class for any property (according to the RFC 5545 specification) in iCal-library.

A property always exists of three parts:

  • The name of the property.
  • The property parameters, this is optional and does not need to be present.
  • The value of the property.

A line containing a property typically has the following format: PROPERTY-NAME;parameterKey=parameterValue,anotherParameterKey=anotherValue:actual-value

Any property that is predefined according to the RFC 5545 should inherit this class, e.g. UID, RRule. Only x-properties or iana-properties should instantiate the Property class directly.

Parameters:

Name Type Description Default
value Optional[str]

The value of the property.

required
name Optional[str]

The properties name, e.g. RRULE.

None
property_parameters Optional[str]

The property parameters for this definition.

None
parent Component

Instance of the :class:Component it is a part of.

None
Source code in ical_library/base_classes/property.py
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
class Property(ICalBaseClass):
    """
    This is the base class for any property (according to the RFC 5545 specification) in iCal-library.

    A property always exists of three parts:

    - The name of the property.
    - The property parameters, this is optional and does not need to be present.
    - The value of the property.

    A line containing a property typically has the following format:
    `PROPERTY-NAME;parameterKey=parameterValue,anotherParameterKey=anotherValue:actual-value`

    Any property that is predefined according to the RFC 5545 should inherit this class, e.g. UID, RRule.
    Only x-properties or iana-properties should instantiate the Property class directly.

    :param value: The value of the property.
    :param name: The properties name, e.g. `RRULE`.
    :param property_parameters: The property parameters for this definition.
    :param parent: Instance of the :class:`Component` it is a part of.
    """

    def __init__(
        self,
        value: Optional[str],
        name: Optional[str] = None,
        property_parameters: Optional[str] = None,
        parent: "Component" = None,
    ):
        name = name if self.__class__ == Property else self.__class__.get_ical_name_of_class()
        super().__init__(name=name, parent=parent or ComponentContext.get_current_component())
        if parent is None and self.parent is not None:
            self.parent.set_property(self)

        self._property_parameters: Optional[str] = property_parameters
        self._value: Optional[str] = value

    def __repr__(self) -> str:
        """Overwrite the repr to create a better representation for the item."""
        return f"{self.__class__.__name__}({self.as_original_string})"

    def __eq__(self: "Property", other: "Property") -> bool:
        """Return whether the current instance and the other instance are the same."""
        if type(self) != type(other):
            return False
        return self.as_original_string == other.as_original_string

    @property
    @instance_lru_cache()
    def property_parameters(self) -> Dict[str, str]:
        """
        Return (and cache) all the property's parameters as a dictionary of strings.

        Note: When the instance is collected by the garbage collection, the cache is automatically deleted as well.

        :return: all the property's parameters as a dictionary of strings
        """
        property_parameters_str = self._property_parameters or ""
        return {
            key_and_value.split("=")[0]: key_and_value.split("=")[1]
            for key_and_value in property_parameters_str.split(",")
            if key_and_value.count("=") == 1
        }

    def has_property_parameter(self, key: str) -> Optional[bool]:
        """
        Return whether this property has a property parameter with a specific *key*.

        :param key: What key to search for.
        :return: boolean whether this property has a property parameter with a specific *key*.
        """
        return key in self.property_parameters

    def get_property_parameter(self, key: str) -> Optional[str]:
        """
        Get a property parameter's value with a specific key.

        :param key: The identifier of the property parameter.
        :return: The requested property parameter, or if that is not present, the default value.
        """
        return self.property_parameters.get(key, None)

    def get_property_parameter_default(self, key: str, default: str) -> str:
        """
        Get a property parameter's value with a specific key, where the default may not be None.

        :param key: The identifier of the property parameter.
        :param default: A value to return when the property parameter is not present, which may not be None.
        :return: The requested property parameter, or if that is not present, the default value.
        """
        return self.property_parameters.get(key, default)

    @property
    def value(self) -> Optional[str]:
        """Return the value of this property."""
        return self._value

    @property
    def as_original_string(self) -> str:
        """
        Return the iCalendar representation of the parameter.
        :return: the iCalendar string representation.
        """
        add_subs = f";{self._property_parameters}" if self._property_parameters else ""
        return f"{self._name}{add_subs}:{self._value}"

as_original_string: str property

Return the iCalendar representation of the parameter.

Returns:

Type Description

the iCalendar string representation.

property_parameters: Dict[str, str] property

Return (and cache) all the property's parameters as a dictionary of strings.

Note: When the instance is collected by the garbage collection, the cache is automatically deleted as well.

Returns:

Type Description

all the property's parameters as a dictionary of strings

value: Optional[str] property

Return the value of this property.

get_property_parameter(key)

Get a property parameter's value with a specific key.

Parameters:

Name Type Description Default
key str

The identifier of the property parameter.

required

Returns:

Type Description
Optional[str]

The requested property parameter, or if that is not present, the default value.

Source code in ical_library/base_classes/property.py
84
85
86
87
88
89
90
91
def get_property_parameter(self, key: str) -> Optional[str]:
    """
    Get a property parameter's value with a specific key.

    :param key: The identifier of the property parameter.
    :return: The requested property parameter, or if that is not present, the default value.
    """
    return self.property_parameters.get(key, None)

get_property_parameter_default(key, default)

Get a property parameter's value with a specific key, where the default may not be None.

Parameters:

Name Type Description Default
key str

The identifier of the property parameter.

required
default str

A value to return when the property parameter is not present, which may not be None.

required

Returns:

Type Description
str

The requested property parameter, or if that is not present, the default value.

Source code in ical_library/base_classes/property.py
 93
 94
 95
 96
 97
 98
 99
100
101
def get_property_parameter_default(self, key: str, default: str) -> str:
    """
    Get a property parameter's value with a specific key, where the default may not be None.

    :param key: The identifier of the property parameter.
    :param default: A value to return when the property parameter is not present, which may not be None.
    :return: The requested property parameter, or if that is not present, the default value.
    """
    return self.property_parameters.get(key, default)

has_property_parameter(key)

Return whether this property has a property parameter with a specific key.

Parameters:

Name Type Description Default
key str

What key to search for.

required

Returns:

Type Description
Optional[bool]

boolean whether this property has a property parameter with a specific key.

Source code in ical_library/base_classes/property.py
75
76
77
78
79
80
81
82
def has_property_parameter(self, key: str) -> Optional[bool]:
    """
    Return whether this property has a property parameter with a specific *key*.

    :param key: What key to search for.
    :return: boolean whether this property has a property parameter with a specific *key*.
    """
    return key in self.property_parameters

Action

Bases: Property

The ACTION property defines the action to be invoked when an alarm is triggered.

Source code in ical_library/ical_properties/pass_properties.py
126
127
128
129
class Action(Property):
    """The ACTION property defines the action to be invoked when an alarm is triggered."""

    pass

Attach

Bases: Property

The ATTACH property provides the capability to associate a document object with a calendar component.

Source code in ical_library/ical_properties/pass_properties.py
76
77
78
79
class Attach(Property):
    """The ATTACH property provides the capability to associate a document object with a calendar component."""

    pass

Attendee

Bases: _CalAddress

The ATTENDEE property defines an "Attendee" within a calendar component.

Source code in ical_library/ical_properties/cal_address.py
40
41
42
43
class Attendee(_CalAddress):
    """The ATTENDEE property defines an "Attendee" within a calendar component."""

    pass

CalScale

Bases: Property

The CALSCALE property defines the calendar scale used for the calendar information specified in the iCalendar object.

Source code in ical_library/ical_properties/pass_properties.py
19
20
21
22
23
24
25
class CalScale(Property):
    """
    The CALSCALE property defines the calendar scale used for the calendar information specified in the iCalendar
    object.
    """

    pass

Categories

Bases: Property

The CATEGORIES property defines the categories for a calendar component.

Source code in ical_library/ical_properties/pass_properties.py
82
83
84
85
class Categories(Property):
    """The CATEGORIES property defines the categories for a calendar component."""

    pass

Class

Bases: Property

The CLASS property defines the access classification for a calendar component.

Source code in ical_library/ical_properties/pass_properties.py
34
35
36
37
class Class(Property):
    """The CLASS property defines the access classification for a calendar component."""

    pass

Comment

Bases: Property

The COMMENT property specifies non-processing information intended to provide a comment to the calendar user.

Source code in ical_library/ical_properties/pass_properties.py
138
139
140
141
class Comment(Property):
    """The COMMENT property specifies non-processing information intended to provide a comment to the calendar user."""

    pass

Completed

Bases: _DTSingular

The COMPLETED property defines the date and time that a to-do was actually completed.

Source code in ical_library/ical_properties/dt.py
106
107
108
109
class Completed(_DTSingular):
    """The COMPLETED property defines the date and time that a to-do was actually completed."""

    pass

Contact

Bases: Property

The CONTACT property is used to represent contact information or alternately a reference to contact information associated with the calendar component.

Source code in ical_library/ical_properties/pass_properties.py
88
89
90
91
92
93
94
class Contact(Property):
    """
    The CONTACT property is used to represent contact information or alternately a reference to contact information
    associated with the calendar component.
    """

    pass

Created

Bases: _DTSingular

The CREATED property defines the date and time that the calendar information was created by the calendar user agent in the calendar store.

Source code in ical_library/ical_properties/dt.py
113
114
115
116
117
118
119
class Created(_DTSingular):
    """
    The CREATED property defines the date and time that the calendar information was created by the calendar
    user agent in the calendar store.
    """

    pass

DTEnd

Bases: _DTBoth

The DTEND property specifies the date and time that a calendar component ends.

Source code in ical_library/ical_properties/dt.py
60
61
62
63
class DTEnd(_DTBoth):
    """The DTEND property specifies the date and time that a calendar component ends."""

    pass

DTStamp

Bases: _DTBoth

The DTSTAMP property is defined as followed.

In the case of an iCalendar object that specifies a "METHOD" property, this property specifies the date and time that the instance of the iCalendar object was created. In the case of an iCalendar object that doesn't specify a "METHOD" property, this property specifies the date and time that the information associated with the calendar component was last revised in the calendar store.

Source code in ical_library/ical_properties/dt.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
class DTStamp(_DTBoth):
    """The DTSTAMP property is defined as followed.

    In the case of an iCalendar object that specifies a "METHOD" property, this property specifies the date and time
    that the instance of the iCalendar object was created. In the case of an iCalendar object that doesn't specify a
    "METHOD" property, this property specifies the date and time that the information associated with the calendar
    component was last revised in the calendar store.
    """

    pass

DTStart

Bases: _DTBoth

The DTSTART property specifies when the calendar component begins..

Source code in ical_library/ical_properties/dt.py
53
54
55
56
class DTStart(_DTBoth):
    """The DTSTART property specifies when the calendar component begins.."""

    pass

Description

Bases: Property

The DESCRIPTION property provides a more complete description of the calendar component than that provided by the "SUMMARY" property.

Source code in ical_library/ical_properties/pass_properties.py
40
41
42
43
44
45
46
class Description(Property):
    """
    The DESCRIPTION property provides a more complete description of the calendar component than that provided by
    the "SUMMARY" property.
    """

    pass

Due

Bases: _DTBoth

This DUE property defines the date and time that a to-do is expected to be completed..

Source code in ical_library/ical_properties/dt.py
67
68
69
70
class Due(_DTBoth):
    """This DUE property defines the date and time that a to-do is expected to be completed.."""

    pass

EXDate

Bases: _ExOrRDate

The EXDATE property defines the list of DATE-TIME exceptions for recurring events, to-dos, journal entries, or time zone definitions.

Source code in ical_library/ical_properties/periods.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
class EXDate(_ExOrRDate):
    """
    The EXDATE property defines the list of DATE-TIME exceptions for recurring events, to-dos, journal entries,
    or time zone definitions.
    """

    @property
    def kind(self) -> Optional[Literal["DATE-TIME", "DATE"]]:
        """The kind of the values. It is either DATE-TIME or DATE. The default is DATE-TIME."""
        return self.property_parameters.get("VALUE", "DATE-TIME")

    @property
    def excluded_date_times(self) -> Union[List[DateTime], List[Date]]:
        """A list of all excluded Dates or DateTimes. The type will be according to kind reported by `self.kind()`."""
        if self.kind == "DATE-TIME":
            return self._parse_datetime_values()
        elif self.kind == "DATE":
            return self._parse_date_values()
        else:
            raise ValueError(f"{self.kind=} should be one in ['DATE-TIME', 'DATE'].")

excluded_date_times: Union[List[DateTime], List[Date]] property

A list of all excluded Dates or DateTimes. The type will be according to kind reported by self.kind().

kind: Optional[Literal['DATE-TIME', 'DATE']] property

The kind of the values. It is either DATE-TIME or DATE. The default is DATE-TIME.

FreeBusyProperty

Bases: _PeriodFunctionality

The FREEBUSY property defines one or more free or busy time intervals.

Note: This class is called FreeBusyProperty to not be confused with the VFreeBusy component.

Source code in ical_library/ical_properties/periods.py
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
class FreeBusyProperty(_PeriodFunctionality):
    """
    The FREEBUSY property defines one or more free or busy time intervals.

    Note: This class is called FreeBusyProperty to not be confused with the VFreeBusy component.
    """

    @classmethod
    def get_ical_name_of_class(cls) -> str:
        """Overwrite the iCal name of this class as it is not *FREEBUSYPROPERTY* but *FREEBUSY*."""
        return "FREEBUSY"

    @property
    def free_busy_type(self) -> str:
        """
        Specifies the free or busy time type.

        Values are usually in the following list but can be anything: FREE, BUSY, BUSY-UNAVAILABLE, BUSY-TENTATIVE
        """
        return self.get_property_parameter_default("FBTYPE", "BUSY")

    @property
    def periods(self) -> List[Tuple[DateTime, DateTime]]:
        """
        All the periods present in this property for which we define a free or busy time.
        :return: A list of tuples, where each tuple values consists of two DateTimes indicating the start and end
        respectively.
        """
        return self._parse_period_values()

free_busy_type: str property

Specifies the free or busy time type.

Values are usually in the following list but can be anything: FREE, BUSY, BUSY-UNAVAILABLE, BUSY-TENTATIVE

periods: List[Tuple[DateTime, DateTime]] property

All the periods present in this property for which we define a free or busy time.

Returns:

Type Description

A list of tuples, where each tuple values consists of two DateTimes indicating the start and end respectively.

get_ical_name_of_class() classmethod

Overwrite the iCal name of this class as it is not FREEBUSYPROPERTY but FREEBUSY.

Source code in ical_library/ical_properties/periods.py
121
122
123
124
@classmethod
def get_ical_name_of_class(cls) -> str:
    """Overwrite the iCal name of this class as it is not *FREEBUSYPROPERTY* but *FREEBUSY*."""
    return "FREEBUSY"

GEO

Bases: Property

The GEO property specifies information related to the global position for the activity specified by a calendar component.

Source code in ical_library/ical_properties/geo.py
 6
 7
 8
 9
10
11
12
13
14
15
16
class GEO(Property):
    """
    The GEO property specifies information related to the global position for the activity specified by a calendar
    component.
    """

    @property
    def geo_value(self) -> Tuple[float, float]:
        """Return the value as two floats representing the latitude and longitude."""
        latitude, longitude = self.value.split(";")
        return float(latitude), float(longitude)

geo_value: Tuple[float, float] property

Return the value as two floats representing the latitude and longitude.

ICALDuration

Bases: Property

The DURATION property specifies a positive duration of time.

Source code in ical_library/ical_properties/ical_duration.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class ICALDuration(Property):
    """The DURATION property specifies a positive duration of time."""

    @property
    def duration(self) -> pendulum.Duration:
        """Return the value as a parsed pendulum.Duration. Example value: PT1H0M0S."""
        parsed_value: pendulum.Duration = pendulum.parse(self.value)
        if not isinstance(parsed_value, pendulum.Duration):
            raise TypeError(f"Invalid value passed for Duration: {self.value=}")
        return parsed_value

    @classmethod
    def get_ical_name_of_class(cls) -> str:
        """Overwrite the iCal name of this class as it is not *ICALDURATION* but *DURATION*."""
        return "DURATION"

duration: pendulum.Duration property

Return the value as a parsed pendulum.Duration. Example value: PT1H0M0S.

get_ical_name_of_class() classmethod

Overwrite the iCal name of this class as it is not ICALDURATION but DURATION.

Source code in ical_library/ical_properties/ical_duration.py
17
18
19
20
@classmethod
def get_ical_name_of_class(cls) -> str:
    """Overwrite the iCal name of this class as it is not *ICALDURATION* but *DURATION*."""
    return "DURATION"

LastModified

Bases: _DTSingular

The LAST-MODIFIED property specifies the date and time that the information associated with the calendar component was last revised in the calendar store.

Source code in ical_library/ical_properties/dt.py
123
124
125
126
127
128
129
130
131
132
class LastModified(_DTSingular):
    """
    The LAST-MODIFIED property specifies the date and time that the information associated with the calendar component
    was last revised in the calendar store.
    """

    @classmethod
    def get_ical_name_of_class(cls) -> str:
        """Overwrite the iCal name of this class as it is not *LASTMODIFIED* but *LAST-MODIFIED*."""
        return "LAST-MODIFIED"

get_ical_name_of_class() classmethod

Overwrite the iCal name of this class as it is not LASTMODIFIED but LAST-MODIFIED.

Source code in ical_library/ical_properties/dt.py
129
130
131
132
@classmethod
def get_ical_name_of_class(cls) -> str:
    """Overwrite the iCal name of this class as it is not *LASTMODIFIED* but *LAST-MODIFIED*."""
    return "LAST-MODIFIED"

Location

Bases: Property

The LOCATION property defines the intended venue for the activity defined by a calendar component.

Source code in ical_library/ical_properties/pass_properties.py
49
50
51
52
class Location(Property):
    """The LOCATION property defines the intended venue for the activity defined by a calendar component."""

    pass

Method

Bases: Property

The METHOD property defines the iCalendar object method associated with the calendar object.

Source code in ical_library/ical_properties/pass_properties.py
28
29
30
31
class Method(Property):
    """The METHOD property defines the iCalendar object method associated with the calendar object."""

    pass

Organizer

Bases: _CalAddress

The ORGANIZER property defines the organizer for a calendar component.

Source code in ical_library/ical_properties/cal_address.py
46
47
48
49
class Organizer(_CalAddress):
    """The ORGANIZER property defines the organizer for a calendar component."""

    pass

PercentComplete

Bases: _IntProperty

The PERCENT-COMPLETE property is used by an assignee or delegatee of a to-do to convey the percent completion of a to-do to the "Organizer".

Source code in ical_library/ical_properties/ints.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class PercentComplete(_IntProperty):
    """
    The PERCENT-COMPLETE property is used by an assignee or delegatee of a to-do to convey the percent completion of
    a to-do to the "Organizer".
    """

    @property
    def percentage(self) -> int:
        return self.int_value

    @classmethod
    def get_ical_name_of_class(cls) -> str:
        """Overwrite the iCal name of this class as it is not *PERCENTCOMPLETE* but *PERCENT-COMPLETE*."""
        return "PERCENT-COMPLETE"

get_ical_name_of_class() classmethod

Overwrite the iCal name of this class as it is not PERCENTCOMPLETE but PERCENT-COMPLETE.

Source code in ical_library/ical_properties/ints.py
43
44
45
46
@classmethod
def get_ical_name_of_class(cls) -> str:
    """Overwrite the iCal name of this class as it is not *PERCENTCOMPLETE* but *PERCENT-COMPLETE*."""
    return "PERCENT-COMPLETE"

Priority

Bases: _IntProperty

The PRIORITY property represents the relative priority for a calendar component.

Source code in ical_library/ical_properties/ints.py
13
14
15
16
class Priority(_IntProperty):
    """The PRIORITY property represents the relative priority for a calendar component."""

    pass

ProdID

Bases: Property

The PRODID property specifies the identifier for the product that created the iCalendar object.

Source code in ical_library/ical_properties/pass_properties.py
4
5
6
7
class ProdID(Property):
    """The PRODID property specifies the identifier for the product that created the iCalendar object."""

    pass

RDate

Bases: _ExOrRDate

The RDATE property defines the list of DATE-TIME values for recurring events, to-dos, journal entries, or time zone definitions.

Source code in ical_library/ical_properties/periods.py
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
class RDate(_ExOrRDate):
    """
    The RDATE property defines the list of DATE-TIME values for recurring events, to-dos, journal entries,
    or time zone definitions.
    """

    @property
    def kind(self) -> Optional[Literal["DATE-TIME", "DATE", "PERIOD"]]:
        """The kind of the values. It is either DATE-TIME, DATE or PERIOD. The default is DATE-TIME."""
        return self.property_parameters.get("VALUE", "DATE-TIME")

    @property
    def all_values(self) -> Union[List[DateTime], List[Date], List[Tuple[DateTime, DateTime]]]:
        """
        A list of all recurring Dates, DateTimes or Periods. The periods are defined by tuples containing two
        datetimes representing the start and stop respectively. The returned types in the list will be according to
        the kind reported by `self.kind()`.
        """
        if self.kind == "DATE-TIME":
            return self._parse_datetime_values()
        elif self.kind == "DATE":
            return self._parse_date_values()
        elif self.kind == "PERIOD":
            return self._parse_period_values()
        else:
            raise ValueError(f"{self.kind=} should be one in ['DATE-TIME', 'DATE', 'PERIOD'].")

    def compute_max_end_date(self, component_duration: Duration) -> DateTime:
        """
        To speed up the computation of the Timelines range, it's good to know the ending of the last recurring event
        of a recurrence property. This does not need to be perfect, it should just be an estimate (so we don't check
        EXDate and such).
        :param component_duration: The duration of the component which has the recurring properties.
        :return: An estimate of the maximum end date across all occurrences. This value should always be at least the
        actual highest recurrence end date
        """
        max_value: Optional[DateTime] = None
        for value in self.all_values:
            if isinstance(value, Date):  # This covers both Date and DateTime
                dt: DateTime = dt_utils.convert_time_object_to_datetime(value)
                dt: DateTime = dt + component_duration  # type: ignore  # Pendulum at fault here.
                dt = dt_utils.convert_time_object_to_aware_datetime(dt)
                if max_value is None or dt > max_value:
                    max_value = dt
            elif isinstance(value, tuple) and len(value) == 2:
                dt: DateTime = dt_utils.convert_time_object_to_aware_datetime(value[1])
                if max_value is None or dt > max_value:
                    max_value = dt
            else:
                raise ValueError(f"Unexpected value encountered: {value}.")
        return max_value or DateTime.max

all_values: Union[List[DateTime], List[Date], List[Tuple[DateTime, DateTime]]] property

A list of all recurring Dates, DateTimes or Periods. The periods are defined by tuples containing two datetimes representing the start and stop respectively. The returned types in the list will be according to the kind reported by self.kind().

kind: Optional[Literal['DATE-TIME', 'DATE', 'PERIOD']] property

The kind of the values. It is either DATE-TIME, DATE or PERIOD. The default is DATE-TIME.

compute_max_end_date(component_duration)

To speed up the computation of the Timelines range, it's good to know the ending of the last recurring event of a recurrence property. This does not need to be perfect, it should just be an estimate (so we don't check EXDate and such).

Parameters:

Name Type Description Default
component_duration Duration

The duration of the component which has the recurring properties.

required

Returns:

Type Description
DateTime

An estimate of the maximum end date across all occurrences. This value should always be at least the actual highest recurrence end date

Source code in ical_library/ical_properties/periods.py
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
def compute_max_end_date(self, component_duration: Duration) -> DateTime:
    """
    To speed up the computation of the Timelines range, it's good to know the ending of the last recurring event
    of a recurrence property. This does not need to be perfect, it should just be an estimate (so we don't check
    EXDate and such).
    :param component_duration: The duration of the component which has the recurring properties.
    :return: An estimate of the maximum end date across all occurrences. This value should always be at least the
    actual highest recurrence end date
    """
    max_value: Optional[DateTime] = None
    for value in self.all_values:
        if isinstance(value, Date):  # This covers both Date and DateTime
            dt: DateTime = dt_utils.convert_time_object_to_datetime(value)
            dt: DateTime = dt + component_duration  # type: ignore  # Pendulum at fault here.
            dt = dt_utils.convert_time_object_to_aware_datetime(dt)
            if max_value is None or dt > max_value:
                max_value = dt
        elif isinstance(value, tuple) and len(value) == 2:
            dt: DateTime = dt_utils.convert_time_object_to_aware_datetime(value[1])
            if max_value is None or dt > max_value:
                max_value = dt
        else:
            raise ValueError(f"Unexpected value encountered: {value}.")
    return max_value or DateTime.max

RRule

Bases: Property

The RRULE property defines a rule or repeating pattern for recurring events, to-dos, journal entries, or time zone definitions.

For more in depth restrictions and possibilities we refer you to the RTFC 5545 section 3.3.10. Recurrence Rule.

Source code in ical_library/ical_properties/rrule.py
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
class RRule(Property):
    """
    The RRULE property defines a rule or repeating pattern for recurring events, to-dos, journal entries, or time zone
    definitions.

    For more in depth restrictions and possibilities we refer you to the `RTFC 5545` section `3.3.10. Recurrence Rule`.
    """

    @property
    @instance_lru_cache()
    def value_as_dict(self) -> Dict[str, str]:
        """
        Parse all recurrence rule parts as a dictionary, so it can be used as an easy lookup.
        :return: A dict mapping of str to str containing all recurrence rule parts.
        """
        all_values = [tuple(key_and_value.split("=")) for key_and_value in self._value.split(";")]
        return {key: value for key, value in all_values}

    @property
    def freq(self) -> str:
        """
        The FREQUENCY rule identifies the type of recurrence rule. Possible values are: SECONDLY, MINUTELY, HOURLY,
        DAILY, WEEKLY, MONTHLY and YEARLY.
        This is the only required field.
        :return: The frequency as a string.
        """
        return self.value_as_dict["FREQ"]

    @property
    def freq_dateutil(self) -> int:
        """
        Return the frequency in the format dateutil expects which is a map of the string to an integer.
        :return: An integer in the range of 0 to 6.
        """
        return getattr(base_for_time_periods, self.freq)

    @property
    def until(self) -> Optional[Union[Date, DateTime]]:
        """
        The UNTIL rule defines a DATE or DATE-TIME value that bounds the recurrence rule in an inclusive manner.
        This is optional but may not occur together with COUNT.
        :return: None or a positive integer.
        """
        if (until_value := self.value_as_dict.get("UNTIL", None)) is not None:
            return dt_utils.parse_date_or_datetime(until_value)
        return None

    @property
    def count(self) -> Optional[int]:
        """
        The COUNT rule defines the number of occurrences at which to range-bound the recurrence.
        This is optional but may not occur together with UNTIL.
        :return: None or a positive integer.
        """
        count_value = self.value_as_dict.get("COUNT", None)
        return int(count_value) if count_value else None

    @property
    def interval(self) -> int:
        """
        The INTERVAL rule contains a positive integer representing at which intervals the recurrence rule repeats.
        :return: A positive integer.
        """
        return int(self.value_as_dict.get("INTERVAL", 1))

    @staticmethod
    def convert_str_to_optional_integer_tuple(value: Optional[str]) -> Optional[Tuple[int, ...]]:
        """
        Converts a string to a Tuple of integers.
        :return: None or a Tuple of integers if the value exists, otherwise None.
        """
        if not value:
            return None
        return tuple(int(item) for item in value.split(","))

    @property
    def by_second(self) -> Optional[Tuple[int, ...]]:
        """
        The BYSECOND rule part specifies a COMMA-separated list of seconds within a minute.
        :return: None or a list of integers in the range of 0 to 60.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYSECOND"))

    @property
    def by_minute(self) -> Optional[Tuple[int, ...]]:
        """
        The BYMINUTE rule part specifies a COMMA-separated list of minutes within an hour.
        :return: None or a list of integers in the range of 0 to 59.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYMINUTE"))

    @property
    def by_hour(self) -> Optional[Tuple[int, ...]]:
        """
        The BYHOUR rule part specifies a COMMA-separated list of hours of the day.
        :return: None or a list of integers in the range of 0 to 23.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYHOUR"))

    def by_day(self) -> Optional[List[Tuple[Optional[int], Literal["SU", "MO", "TU", "WE", "TH", "FR", "SA"]]]]:
        """
        The BYDAY rule part specifies a COMMA-separated list of days of the week;
        SU indicates Sunday; MO indicates Monday; TU indicates Tuesday; WE indicates Wednesday;
        TH indicates Thursday; FR indicates Friday; and SA indicates Saturday.

        Each BYDAY value can also be preceded by a positive (+n) or negative (-n) integer.
        If present, this indicates the nth occurrence of a specific day within the MONTHLY or YEARLY "RRULE".

        Example values are SU,TU or +2SU,-3TU

        :return None or a list of tuples of two values. The first value represents possible specified nth occurrence or
        None. The second value the day of the week as a SU, MO, TU, WE, TH, FR or SA.
        """
        value = self.value_as_dict.get("BYDAY")
        if not value:
            return None
        list_of_days: List[Tuple[Optional[int], Literal["SU", "MO", "TU", "WE", "TH", "FR", "SA"]]] = []
        for a_day in value.split(","):
            a_day = a_day.strip()
            nth_occurence: Optional[int] = int(a_day[:-2]) if len(a_day) > 2 else None
            day_of_week: str = a_day[-2:]
            if day_of_week not in ("SU", "MO", "TU", "WE", "TH", "FR", "SA"):
                raise ValueError
            list_of_days.append((nth_occurence, day_of_week))  # type: ignore
        return list_of_days

    @property
    def by_day_dateutil(self) -> Optional[Tuple[weekday, ...]]:
        """
        Return the by_day in the format dateutil expects which is a tuple of weekday instance.
        :return: None or a tuple of weekday instances which is a type native to dateutil.
        """
        day_list: List[weekday] = []
        by_day = self.by_day()
        if by_day is None:
            return None
        for optional_nth_occurrence, weekday_str in by_day:
            try:
                if optional_nth_occurrence is not None:
                    day_list.append(getattr(base_for_time_periods, weekday_str)(optional_nth_occurrence))
                else:
                    day_list.append(getattr(base_for_time_periods, weekday_str))
            except Exception as exc:
                raise ValueError(f"{optional_nth_occurrence=}, {weekday_str=}") from exc
        return tuple(day_list)

    @property
    def by_month_day(self) -> Optional[Tuple[int, ...]]:
        """
        The BYMONTHDAY rule part specifies a COMMA-separated list of days of the month.
        For example: -10 represents the tenth to the last day of the month.
        :return: None or a tuple of integers in the range of 1 to 31 or -31 to -1.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYMONTHDAY"))

    @property
    def by_year_day(self) -> Optional[Tuple[int, ...]]:
        """
        The BYYEARDAY rule part specifies a COMMA-separated list of days of the year.
        For example: -1 represents the last day of the year (December 31st).
        :return: None or a tuple of integers in the range of 1 to 366 or -366 to -1.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYYEARDAY"))

    @property
    def by_week_no(self) -> Optional[Tuple[int, ...]]:
        """
        The BYWEEKNO rule part specifies a COMMA-separated list of ordinals specifying weeks of the year.
        For example: 3 represents the third week of the year.
        :return: None or an integer in the range of 1 to 53 or -53 to -1.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYWEEKNO"))

    @property
    def by_month(self) -> Optional[Tuple[int, ...]]:
        """
        The BYMONTH rule part specifies a COMMA-separated list of months of the year.
        :return: None or a list of integers in the range of 1 to 12.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYMONTH"))

    @property
    def by_set_pos(self) -> Optional[Tuple[int, ...]]:
        """
        The BYSETPOS rule part specifies a COMMA-separated list of values that corresponds to the nth occurrence within
        the set of recurrence instances specified by the rule. BYSETPOS operates on a set of recurrence instances in
        one interval of the recurrence rule. For example, in a WEEKLY rule, the interval would be one week A set of
        recurrence instances starts at the beginning of the interval defined by the FREQ rule part.
        :return: None or a list of integers in the range of 1 to 366 or -366 to -1.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYSETPOS"))

    @property
    def wkst(self) -> Optional[str]:
        """
        The WKST rule part specifies the day on which the workweek starts.
        :return: A string that is the value of MO, TU, WE, TH, FR, SA, or SU or None.
        """
        day = self.value_as_dict.get("WKST")
        if not day:
            return None
        if day not in ("SU", "MO", "TU", "WE", "TH", "FR", "SA"):
            raise ValueError(f"{day=} is not in the list of weekdays.")
        return day

    @property
    def wkst_dateutil(self) -> Optional[int]:
        """
        Return the wkst in the format dateutil expects which is an integer. 0 for MO, 1 for TU, 2 for WE, ...
        :return: An integer in the range of 0 to 6 or None.
        """
        day = self.wkst
        return getattr(base_for_time_periods, day) if self.wkst is not None else None

    @property
    def by_easter(self) -> Optional[Tuple[int, ...]]:
        """
        According to dateutil, this is an extension of the RFC specification.. I can't find it. If anyone can, please
        file an issue or a PR to add it here as a reference.

        The BYEASTER rule part specifies the offset from the Easter Sunday.
        :return: None or an integer in the range of 1 to 366 or -366 to -1 or None.
        """
        return self.convert_str_to_optional_integer_tuple(self.value_as_dict.get("BYEASTER"))

    def compute_max_end_date(self, starting_datetime: Union[Date, DateTime], component_duration: Duration) -> DateTime:
        """
        To speed up the computation of the Timelines range, it's good to know the ending of the last recurring event
        of a recurrence property. This does not need to be perfect, it should just be an estimate (so we don't check
        EXDate and such).
        :param starting_datetime: The starting datetime from which we start computing the next occurrences.
        :param component_duration: The duration of the component which has the recurring properties.
        :return: An estimate of the maximum end date across all occurrences. This value should always be at least the
        actual highest recurrence end date
        """
        if self.until:
            return dt_utils.convert_time_object_to_aware_datetime(self.until) + component_duration  # type: ignore
        elif self.count:
            if self.count < 1000:
                max_datetime = DateTime.max if isinstance(starting_datetime, DateTime) else Date(9999, 12, 31)
                *_, last = self.sequence_iterator(starting_datetime=starting_datetime, max_datetime=max_datetime)
                return dt_utils.convert_time_object_to_aware_datetime(last) + component_duration  # type: ignore
        return DateTime.max

    def sequence_iterator(
        self, starting_datetime: Union[Date, DateTime], max_datetime: Union[Date, DateTime]
    ) -> Iterator[DateTime]:
        """
        Given a starting datetime, we compute dates according to the RRule specification until the end of the sequence
        according to the specification is reached or until we reached the max_datetime.
        :param starting_datetime: The starting datetime from which we start computing the next occurrences.
        :param max_datetime: The maximum datetime. If we reach this datetime, we stop the iteration..
        :return: Yield all datetimes(except itself) in the sequence.
        """
        if type(starting_datetime) != type(max_datetime):
            raise TypeError(f"{type(starting_datetime)=} and {type(max_datetime)=} should be of the same type.")
        if isinstance(starting_datetime, DateTime):
            if (starting_datetime.tz or max_datetime.tz) and (not starting_datetime.tz or not max_datetime.tz):
                raise TypeError(f"The tz info should be consistent: {starting_datetime=}, {max_datetime=}.")
        if not isinstance(starting_datetime, (Date, DateTime)) or not isinstance(max_datetime, (Date, DateTime)):
            raise TypeError(f"{type(starting_datetime)=} and {type(max_datetime)=} should be of Date or DateTime.")
        if starting_datetime > max_datetime:
            raise ValueError(f"This should not be the case: {starting_datetime=} >= {max_datetime=} .")

        if not (is_datetime_format := isinstance(starting_datetime, DateTime) and isinstance(max_datetime, DateTime)):
            starting_datetime = DateTime(starting_datetime.year, starting_datetime.month, starting_datetime.day)
            max_datetime = DateTime(max_datetime.year, max_datetime.month, max_datetime.day)

        starting_datetime = starting_datetime
        max_datetime = max_datetime
        starting_tz = starting_datetime.tz
        until = self.until
        if until:
            if not isinstance(until, DateTime):
                until = DateTime(until.year, until.month, until.day)
            until = until.replace(tzinfo=None) if starting_tz is None else until.in_timezone(starting_tz)

        keyword_arguments = {
            "until": until,
            "count": self.count,
            "interval": self.interval,
            "bysecond": self.by_second,
            "byminute": self.by_minute,
            "byhour": self.by_hour,
            "byweekday": self.by_day_dateutil,
            "bymonthday": self.by_month_day,
            "byyearday": self.by_year_day,
            "byweekno": self.by_week_no,
            "bymonth": self.by_month,
            "bysetpos": self.by_set_pos,
            "wkst": self.wkst_dateutil,
            "byeaster": self.by_easter,
        }
        no_none_keywords = {key: value for key, value in keyword_arguments.items() if value is not None}
        dt_iterator = rrule(dtstart=starting_datetime, freq=self.freq_dateutil, **no_none_keywords)
        for dt in dt_iterator:
            if dt > max_datetime:
                break
            p_instance = pendulum.instance(dt, tz=None)
            yield p_instance if is_datetime_format else p_instance.date()

by_day_dateutil: Optional[Tuple[weekday, ...]] property

Return the by_day in the format dateutil expects which is a tuple of weekday instance.

Returns:

Type Description

None or a tuple of weekday instances which is a type native to dateutil.

by_easter: Optional[Tuple[int, ...]] property

According to dateutil, this is an extension of the RFC specification.. I can't find it. If anyone can, please file an issue or a PR to add it here as a reference.

The BYEASTER rule part specifies the offset from the Easter Sunday.

Returns:

Type Description

None or an integer in the range of 1 to 366 or -366 to -1 or None.

by_hour: Optional[Tuple[int, ...]] property

The BYHOUR rule part specifies a COMMA-separated list of hours of the day.

Returns:

Type Description

None or a list of integers in the range of 0 to 23.

by_minute: Optional[Tuple[int, ...]] property

The BYMINUTE rule part specifies a COMMA-separated list of minutes within an hour.

Returns:

Type Description

None or a list of integers in the range of 0 to 59.

by_month: Optional[Tuple[int, ...]] property

The BYMONTH rule part specifies a COMMA-separated list of months of the year.

Returns:

Type Description

None or a list of integers in the range of 1 to 12.

by_month_day: Optional[Tuple[int, ...]] property

The BYMONTHDAY rule part specifies a COMMA-separated list of days of the month. For example: -10 represents the tenth to the last day of the month.

Returns:

Type Description

None or a tuple of integers in the range of 1 to 31 or -31 to -1.

by_second: Optional[Tuple[int, ...]] property

The BYSECOND rule part specifies a COMMA-separated list of seconds within a minute.

Returns:

Type Description

None or a list of integers in the range of 0 to 60.

by_set_pos: Optional[Tuple[int, ...]] property

The BYSETPOS rule part specifies a COMMA-separated list of values that corresponds to the nth occurrence within the set of recurrence instances specified by the rule. BYSETPOS operates on a set of recurrence instances in one interval of the recurrence rule. For example, in a WEEKLY rule, the interval would be one week A set of recurrence instances starts at the beginning of the interval defined by the FREQ rule part.

Returns:

Type Description

None or a list of integers in the range of 1 to 366 or -366 to -1.

by_week_no: Optional[Tuple[int, ...]] property

The BYWEEKNO rule part specifies a COMMA-separated list of ordinals specifying weeks of the year. For example: 3 represents the third week of the year.

Returns:

Type Description

None or an integer in the range of 1 to 53 or -53 to -1.

by_year_day: Optional[Tuple[int, ...]] property

The BYYEARDAY rule part specifies a COMMA-separated list of days of the year. For example: -1 represents the last day of the year (December 31st).

Returns:

Type Description

None or a tuple of integers in the range of 1 to 366 or -366 to -1.

count: Optional[int] property

The COUNT rule defines the number of occurrences at which to range-bound the recurrence. This is optional but may not occur together with UNTIL.

Returns:

Type Description

None or a positive integer.

freq: str property

The FREQUENCY rule identifies the type of recurrence rule. Possible values are: SECONDLY, MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY and YEARLY. This is the only required field.

Returns:

Type Description

The frequency as a string.

freq_dateutil: int property

Return the frequency in the format dateutil expects which is a map of the string to an integer.

Returns:

Type Description

An integer in the range of 0 to 6.

interval: int property

The INTERVAL rule contains a positive integer representing at which intervals the recurrence rule repeats.

Returns:

Type Description

A positive integer.

until: Optional[Union[Date, DateTime]] property

The UNTIL rule defines a DATE or DATE-TIME value that bounds the recurrence rule in an inclusive manner. This is optional but may not occur together with COUNT.

Returns:

Type Description

None or a positive integer.

value_as_dict: Dict[str, str] property

Parse all recurrence rule parts as a dictionary, so it can be used as an easy lookup.

Returns:

Type Description

A dict mapping of str to str containing all recurrence rule parts.

wkst: Optional[str] property

The WKST rule part specifies the day on which the workweek starts.

Returns:

Type Description

A string that is the value of MO, TU, WE, TH, FR, SA, or SU or None.

wkst_dateutil: Optional[int] property

Return the wkst in the format dateutil expects which is an integer. 0 for MO, 1 for TU, 2 for WE, ...

Returns:

Type Description

An integer in the range of 0 to 6 or None.

by_day()

The BYDAY rule part specifies a COMMA-separated list of days of the week; SU indicates Sunday; MO indicates Monday; TU indicates Tuesday; WE indicates Wednesday; TH indicates Thursday; FR indicates Friday; and SA indicates Saturday.

Each BYDAY value can also be preceded by a positive (+n) or negative (-n) integer. If present, this indicates the nth occurrence of a specific day within the MONTHLY or YEARLY "RRULE".

Example values are SU,TU or +2SU,-3TU

Source code in ical_library/ical_properties/rrule.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
def by_day(self) -> Optional[List[Tuple[Optional[int], Literal["SU", "MO", "TU", "WE", "TH", "FR", "SA"]]]]:
    """
    The BYDAY rule part specifies a COMMA-separated list of days of the week;
    SU indicates Sunday; MO indicates Monday; TU indicates Tuesday; WE indicates Wednesday;
    TH indicates Thursday; FR indicates Friday; and SA indicates Saturday.

    Each BYDAY value can also be preceded by a positive (+n) or negative (-n) integer.
    If present, this indicates the nth occurrence of a specific day within the MONTHLY or YEARLY "RRULE".

    Example values are SU,TU or +2SU,-3TU

    :return None or a list of tuples of two values. The first value represents possible specified nth occurrence or
    None. The second value the day of the week as a SU, MO, TU, WE, TH, FR or SA.
    """
    value = self.value_as_dict.get("BYDAY")
    if not value:
        return None
    list_of_days: List[Tuple[Optional[int], Literal["SU", "MO", "TU", "WE", "TH", "FR", "SA"]]] = []
    for a_day in value.split(","):
        a_day = a_day.strip()
        nth_occurence: Optional[int] = int(a_day[:-2]) if len(a_day) > 2 else None
        day_of_week: str = a_day[-2:]
        if day_of_week not in ("SU", "MO", "TU", "WE", "TH", "FR", "SA"):
            raise ValueError
        list_of_days.append((nth_occurence, day_of_week))  # type: ignore
    return list_of_days

compute_max_end_date(starting_datetime, component_duration)

To speed up the computation of the Timelines range, it's good to know the ending of the last recurring event of a recurrence property. This does not need to be perfect, it should just be an estimate (so we don't check EXDate and such).

Parameters:

Name Type Description Default
starting_datetime Union[Date, DateTime]

The starting datetime from which we start computing the next occurrences.

required
component_duration Duration

The duration of the component which has the recurring properties.

required

Returns:

Type Description
DateTime

An estimate of the maximum end date across all occurrences. This value should always be at least the actual highest recurrence end date

Source code in ical_library/ical_properties/rrule.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
def compute_max_end_date(self, starting_datetime: Union[Date, DateTime], component_duration: Duration) -> DateTime:
    """
    To speed up the computation of the Timelines range, it's good to know the ending of the last recurring event
    of a recurrence property. This does not need to be perfect, it should just be an estimate (so we don't check
    EXDate and such).
    :param starting_datetime: The starting datetime from which we start computing the next occurrences.
    :param component_duration: The duration of the component which has the recurring properties.
    :return: An estimate of the maximum end date across all occurrences. This value should always be at least the
    actual highest recurrence end date
    """
    if self.until:
        return dt_utils.convert_time_object_to_aware_datetime(self.until) + component_duration  # type: ignore
    elif self.count:
        if self.count < 1000:
            max_datetime = DateTime.max if isinstance(starting_datetime, DateTime) else Date(9999, 12, 31)
            *_, last = self.sequence_iterator(starting_datetime=starting_datetime, max_datetime=max_datetime)
            return dt_utils.convert_time_object_to_aware_datetime(last) + component_duration  # type: ignore
    return DateTime.max

convert_str_to_optional_integer_tuple(value) staticmethod

Converts a string to a Tuple of integers.

Returns:

Type Description
Optional[Tuple[int, ...]]

None or a Tuple of integers if the value exists, otherwise None.

Source code in ical_library/ical_properties/rrule.py
78
79
80
81
82
83
84
85
86
@staticmethod
def convert_str_to_optional_integer_tuple(value: Optional[str]) -> Optional[Tuple[int, ...]]:
    """
    Converts a string to a Tuple of integers.
    :return: None or a Tuple of integers if the value exists, otherwise None.
    """
    if not value:
        return None
    return tuple(int(item) for item in value.split(","))

sequence_iterator(starting_datetime, max_datetime)

Given a starting datetime, we compute dates according to the RRule specification until the end of the sequence according to the specification is reached or until we reached the max_datetime.

Parameters:

Name Type Description Default
starting_datetime Union[Date, DateTime]

The starting datetime from which we start computing the next occurrences.

required
max_datetime Union[Date, DateTime]

The maximum datetime. If we reach this datetime, we stop the iteration..

required

Returns:

Type Description
Iterator[DateTime]

Yield all datetimes(except itself) in the sequence.

Source code in ical_library/ical_properties/rrule.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
def sequence_iterator(
    self, starting_datetime: Union[Date, DateTime], max_datetime: Union[Date, DateTime]
) -> Iterator[DateTime]:
    """
    Given a starting datetime, we compute dates according to the RRule specification until the end of the sequence
    according to the specification is reached or until we reached the max_datetime.
    :param starting_datetime: The starting datetime from which we start computing the next occurrences.
    :param max_datetime: The maximum datetime. If we reach this datetime, we stop the iteration..
    :return: Yield all datetimes(except itself) in the sequence.
    """
    if type(starting_datetime) != type(max_datetime):
        raise TypeError(f"{type(starting_datetime)=} and {type(max_datetime)=} should be of the same type.")
    if isinstance(starting_datetime, DateTime):
        if (starting_datetime.tz or max_datetime.tz) and (not starting_datetime.tz or not max_datetime.tz):
            raise TypeError(f"The tz info should be consistent: {starting_datetime=}, {max_datetime=}.")
    if not isinstance(starting_datetime, (Date, DateTime)) or not isinstance(max_datetime, (Date, DateTime)):
        raise TypeError(f"{type(starting_datetime)=} and {type(max_datetime)=} should be of Date or DateTime.")
    if starting_datetime > max_datetime:
        raise ValueError(f"This should not be the case: {starting_datetime=} >= {max_datetime=} .")

    if not (is_datetime_format := isinstance(starting_datetime, DateTime) and isinstance(max_datetime, DateTime)):
        starting_datetime = DateTime(starting_datetime.year, starting_datetime.month, starting_datetime.day)
        max_datetime = DateTime(max_datetime.year, max_datetime.month, max_datetime.day)

    starting_datetime = starting_datetime
    max_datetime = max_datetime
    starting_tz = starting_datetime.tz
    until = self.until
    if until:
        if not isinstance(until, DateTime):
            until = DateTime(until.year, until.month, until.day)
        until = until.replace(tzinfo=None) if starting_tz is None else until.in_timezone(starting_tz)

    keyword_arguments = {
        "until": until,
        "count": self.count,
        "interval": self.interval,
        "bysecond": self.by_second,
        "byminute": self.by_minute,
        "byhour": self.by_hour,
        "byweekday": self.by_day_dateutil,
        "bymonthday": self.by_month_day,
        "byyearday": self.by_year_day,
        "byweekno": self.by_week_no,
        "bymonth": self.by_month,
        "bysetpos": self.by_set_pos,
        "wkst": self.wkst_dateutil,
        "byeaster": self.by_easter,
    }
    no_none_keywords = {key: value for key, value in keyword_arguments.items() if value is not None}
    dt_iterator = rrule(dtstart=starting_datetime, freq=self.freq_dateutil, **no_none_keywords)
    for dt in dt_iterator:
        if dt > max_datetime:
            break
        p_instance = pendulum.instance(dt, tz=None)
        yield p_instance if is_datetime_format else p_instance.date()

RecurrenceID

Bases: _DTBoth

The RECURRENCE-ID property is defined as followed.

This property is used in conjunction with the "UID" and "SEQUENCE" properties to identify a specific instance of a recurring "VEVENT", "VTODO", or "VJOURNAL" calendar component. The property value is the original value of the "DTSTART" property of the recurrence instance. Value Type: The default value type is DATE-TIME. The value type can be set to a DATE value type. This property MUST have the same value type as the "DTSTART" property contained within the recurring component. Furthermore, this property MUST be specified as a date with local time if and only if the "DTSTART" property contained within the recurring component is specified as a date with local time.

Source code in ical_library/ical_properties/dt.py
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
class RecurrenceID(_DTBoth):
    """
    The RECURRENCE-ID property is defined as followed.

    This property is used in conjunction with the "UID" and "SEQUENCE" properties to identify a specific instance of
    a recurring "VEVENT", "VTODO", or "VJOURNAL" calendar component. The property value is the original value of the
    "DTSTART" property of the recurrence instance. Value Type: The default value type is DATE-TIME. The value type
    can be set to a DATE value type. This property MUST have the same value type as the "DTSTART" property contained
    within the recurring component. Furthermore, this property MUST be specified as a date with local time if and
    only if the "DTSTART" property contained within the recurring component is specified as a date with local time.
    """

    @classmethod
    def get_ical_name_of_class(cls) -> str:
        """Overwrite the iCal name of this class as it is not *LASTMODIFIED* but *LAST-MODIFIED*."""
        return "RECURRENCE-ID"

get_ical_name_of_class() classmethod

Overwrite the iCal name of this class as it is not LASTMODIFIED but LAST-MODIFIED.

Source code in ical_library/ical_properties/dt.py
86
87
88
89
@classmethod
def get_ical_name_of_class(cls) -> str:
    """Overwrite the iCal name of this class as it is not *LASTMODIFIED* but *LAST-MODIFIED*."""
    return "RECURRENCE-ID"

RelatedTo

Bases: Property

The RELATED-TO property is used to represent a relationship or reference between one calendar component and another.

Source code in ical_library/ical_properties/pass_properties.py
106
107
108
109
110
111
112
113
114
class RelatedTo(Property):
    """
    The RELATED-TO property is used to represent a relationship or reference between one calendar component and another.
    """

    @classmethod
    def get_ical_name_of_class(cls) -> str:
        """Overwrite the iCal name of this class as it is not *RELATEDTO* but *RELATED-TO*."""
        return "RELATED-TO"

get_ical_name_of_class() classmethod

Overwrite the iCal name of this class as it is not RELATEDTO but RELATED-TO.

Source code in ical_library/ical_properties/pass_properties.py
111
112
113
114
@classmethod
def get_ical_name_of_class(cls) -> str:
    """Overwrite the iCal name of this class as it is not *RELATEDTO* but *RELATED-TO*."""
    return "RELATED-TO"

Repeat

Bases: _IntProperty

The REPEAT property defines the number of times the alarm should be repeated, after the initial trigger.

Source code in ical_library/ical_properties/ints.py
27
28
29
30
class Repeat(_IntProperty):
    """The REPEAT property defines the number of times the alarm should be repeated, after the initial trigger."""

    pass

RequestStatus

Bases: Property

The REQUEST-STATUS property defines the status code returned for a scheduling request.

Source code in ical_library/ical_properties/pass_properties.py
 97
 98
 99
100
101
102
103
class RequestStatus(Property):
    """The REQUEST-STATUS property defines the status code returned for a scheduling request."""

    @classmethod
    def get_ical_name_of_class(cls) -> str:
        """Overwrite the iCal name of this class as it is not *REQUESTSTATUS* but *REQUEST-STATUS*."""
        return "REQUEST-STATUS"

get_ical_name_of_class() classmethod

Overwrite the iCal name of this class as it is not REQUESTSTATUS but REQUEST-STATUS.

Source code in ical_library/ical_properties/pass_properties.py
100
101
102
103
@classmethod
def get_ical_name_of_class(cls) -> str:
    """Overwrite the iCal name of this class as it is not *REQUESTSTATUS* but *REQUEST-STATUS*."""
    return "REQUEST-STATUS"

Resources

Bases: Property

The RESOURCES property defines the equipment or resources anticipated for an activity specified by a calendar component.

Source code in ical_library/ical_properties/pass_properties.py
117
118
119
120
121
122
123
class Resources(Property):
    """
    The RESOURCES property defines the equipment or resources anticipated for an activity specified by a calendar
    component.
    """

    pass

Sequence

Bases: _IntProperty

The SEQUENCE property defines the revision sequence number of the calendar component within a sequence of revisions.

Source code in ical_library/ical_properties/ints.py
19
20
21
22
23
24
class Sequence(_IntProperty):
    """
    The SEQUENCE property defines the revision sequence number of the calendar component within a sequence of revisions.
    """

    pass

Status

Bases: Property

The STATUS property defines the overall status or confirmation for the calendar component.

Source code in ical_library/ical_properties/pass_properties.py
55
56
57
58
class Status(Property):
    """The STATUS property defines the overall status or confirmation for the calendar component."""

    pass

Summary

Bases: Property

The SUMMARY property defines a short summary or subject for the calendar component.

Source code in ical_library/ical_properties/pass_properties.py
168
169
170
171
172
173
class Summary(Property):
    """
    The SUMMARY property defines a short summary or subject for the calendar component.
    """

    pass

TZID

Bases: Property

The TZID property specifies the text value that uniquely identifies the "VTIMEZONE" calendar component in the scope of an iCalendar object.

Source code in ical_library/ical_properties/pass_properties.py
150
151
152
153
154
155
156
class TZID(Property):
    """
    The TZID property specifies the text value that uniquely identifies the "VTIMEZONE" calendar component in the scope
    of an iCalendar object.
    """

    pass

TZName

Bases: Property

The TZNAME property specifies the customary designation for a time zone description.

Source code in ical_library/ical_properties/pass_properties.py
144
145
146
147
class TZName(Property):
    """The TZNAME property specifies the customary designation for a time zone description."""

    pass

TZOffsetFrom

Bases: _TZOffset

The TZOFFSETFROM property specifies the offset that is in use prior to this time zone observance.

Source code in ical_library/ical_properties/tz_offset.py
33
34
35
36
class TZOffsetFrom(_TZOffset):
    """The TZOFFSETFROM property specifies the offset that is in use prior to this time zone observance."""

    pass

TZOffsetTo

Bases: _TZOffset

The TZOFFSETTO property specifies the offset that is in use prior to this time zone observance.

Source code in ical_library/ical_properties/tz_offset.py
27
28
29
30
class TZOffsetTo(_TZOffset):
    """The TZOFFSETTO property specifies the offset that is in use prior to this time zone observance."""

    pass

TZURL

Bases: Property

The TZURL property provides a means for a "VTIMEZONE" component to point to a network location that can be used to retrieve an up- to-date version of itself.

Source code in ical_library/ical_properties/pass_properties.py
159
160
161
162
163
164
165
class TZURL(Property):
    """
    The TZURL property provides a means for a "VTIMEZONE" component to point to a network location that can be used to
    retrieve an up- to-date version of itself.
    """

    pass

TimeTransparency

Bases: Property

The TRANSP property defines whether an event is transparent to busy time searches.

Source code in ical_library/ical_properties/pass_properties.py
61
62
63
64
65
66
67
class TimeTransparency(Property):
    """The TRANSP property defines whether an event is transparent to busy time searches."""

    @classmethod
    def get_ical_name_of_class(cls) -> str:
        """Overwrite the iCal name of this class as it is not *TIMETRANSPARANCY* but *TRANSP*."""
        return "TRANSP"

get_ical_name_of_class() classmethod

Overwrite the iCal name of this class as it is not TIMETRANSPARANCY but TRANSP.

Source code in ical_library/ical_properties/pass_properties.py
64
65
66
67
@classmethod
def get_ical_name_of_class(cls) -> str:
    """Overwrite the iCal name of this class as it is not *TIMETRANSPARANCY* but *TRANSP*."""
    return "TRANSP"

Trigger

Bases: Property

The TRIGGER property specifies when an alarm will trigger.

Source code in ical_library/ical_properties/trigger.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Trigger(Property):
    """The TRIGGER property specifies when an alarm will trigger."""

    @property
    def kind(self) -> Literal["DATE-TIME", "DURATION"]:
        """Return the type of the property value."""
        kind_of_value = self.get_property_parameter("VALUE")
        return "DATE-TIME" if kind_of_value and kind_of_value == "DATE-TIME" else "DURATION"  # noqa

    def parse_value(self) -> Union[Duration, DateTime]:
        """Parse the value of this property based on the VALUE property parameter."""
        if self.kind == "DURATION":
            parsed_value: Duration = pendulum.parse(self.value)
            if not isinstance(parsed_value, Duration):
                raise TypeError(f"Invalid value passed for Duration: {self.value=}")
            return parsed_value
        else:
            parsed_value: DateTime = pendulum.parse(self.value)
            if not isinstance(parsed_value, DateTime):
                raise TypeError(f"Invalid value passed for DateTime: {self.value=}")
            return parsed_value

    def trigger_relation(self) -> Literal["START", "END"]:
        """Get the trigger relation, whether the duration should be relative to the start or the end of a component."""
        return "START" if self.get_property_parameter_default("RELATED", "START") == "START" else "END"  # noqa

kind: Literal['DATE-TIME', 'DURATION'] property

Return the type of the property value.

parse_value()

Parse the value of this property based on the VALUE property parameter.

Source code in ical_library/ical_properties/trigger.py
18
19
20
21
22
23
24
25
26
27
28
29
def parse_value(self) -> Union[Duration, DateTime]:
    """Parse the value of this property based on the VALUE property parameter."""
    if self.kind == "DURATION":
        parsed_value: Duration = pendulum.parse(self.value)
        if not isinstance(parsed_value, Duration):
            raise TypeError(f"Invalid value passed for Duration: {self.value=}")
        return parsed_value
    else:
        parsed_value: DateTime = pendulum.parse(self.value)
        if not isinstance(parsed_value, DateTime):
            raise TypeError(f"Invalid value passed for DateTime: {self.value=}")
        return parsed_value

trigger_relation()

Get the trigger relation, whether the duration should be relative to the start or the end of a component.

Source code in ical_library/ical_properties/trigger.py
31
32
33
def trigger_relation(self) -> Literal["START", "END"]:
    """Get the trigger relation, whether the duration should be relative to the start or the end of a component."""
    return "START" if self.get_property_parameter_default("RELATED", "START") == "START" else "END"  # noqa

UID

Bases: Property

The UID property defines the persistent, globally unique identifier for the calendar component.

Source code in ical_library/ical_properties/pass_properties.py
132
133
134
135
class UID(Property):
    """The UID property defines the persistent, globally unique identifier for the calendar component."""

    pass

URL

Bases: Property

The URL property defines a Uniform Resource Locator (URL) associated with the iCalendar object.

Source code in ical_library/ical_properties/pass_properties.py
70
71
72
73
class URL(Property):
    """The URL property defines a Uniform Resource Locator (URL) associated with the iCalendar object."""

    pass

Version

Bases: Property

The VERSION property specifies the identifier corresponding to the highest version number or the minimum and maximum range of the iCalendar specification that is required in order to interpret the iCalendar object.

Source code in ical_library/ical_properties/pass_properties.py
10
11
12
13
14
15
16
class Version(Property):
    """
    The VERSION property specifies the identifier corresponding to the highest version number or the minimum and
    maximum range of the iCalendar specification that is required in order to interpret the iCalendar object.
    """

    pass