API design#

This chapter describes the API design of icalendar.

At their core, iCalendar components are dictionaries with case insensitive keys. The preferred way to access their values is through lower case properties as described in Property access. Advantages and disadvantages of the other approaches are discussed below.

Property access#

Accessing components by their properties is preferred over using the Dictionary access for the following reasons.

  • Values are checked for correctness.

  • Values are converted to the correct type.

  • Properties and parameters are typed for type checking and auto completion in editors when writing code that uses the icalendar package.

  • Default values require fewer logical coding checks for presence.

The example below creates an event with useful default values, using new(). RFC 5545 requires DTSTAMP and UID values to be present. They are automatically added.

>>> from icalendar import Event
>>> from datetime import date
>>> event = Event.new(
...     summary="New Year's Day Celebration",
...     start=date(2022, 1, 1)
... )
>>> print(event.to_ical())
BEGIN:VEVENT
SUMMARY:New Year's Day Celebration
DTSTART;VALUE=DATE:20220101
DTSTAMP:20250517T080612Z
UID:d755cef5-2311-46ed-a0e1-6733c9e15c63
END:VEVENT

Based on the created event above, the following example shows how to access values by their properties.

>>> print(event.summary)
New Year's Day Celebration
>>> print(event.start)
2022-01-01

Property naming convention#

Property names are either in lower case or upper case.

  • Upper case property names refer simultaneously to both the Python component property name and the iCalender RFC 5545 property name. For example, DTEND occurs in RFC 5545 Section 3.6.1 and as a property in Event.

  • Lower case property names refer to only the Python component property name. These properties are calculated from one or more upper case properties. For example, end is calculated either from DTEND or from both DTSTART and DURATION.

All properties can be accessed as attributes.

Lower case properties#

Continuing from the previous example, the next example shows how to access values by attributes.

>>> print(event.summary)
New Year's Day Celebration

While some values are not set, they can be calculated from other values. The event in this example has a duration of one day.

>>> event.start
datetime.date(2022, 1, 1)
>>> event.duration
datetime.timedelta(days=1)
>>> event.end
datetime.date(2022, 1, 2)

While some attributes might be empty, they can have useful default values.

>>> event.rdates  # no RDATE is set
[]

Upper case properties#

Upper case properties are either empty, or None, if they're not set. They can be accessed as attributes.

>>> event.DTSTART
datetime.date(2022, 1, 1)
>>> print(event.DURATION)
None
>>> print(event.DTEND)
None

Parameter properties#

Parameters can be accessed using specified properties.

The following example creates a new attendee for the previously created event from above.

>>> from icalendar import vCalAddress, ROLE
>>> attendee = vCalAddress.new(
...     "maxm@example.com",
...     cn="Max Rasmussen",
...     role=ROLE.REQ_PARTICIPANT
... )
>>> print(attendee.ROLE)
REQ-PARTICIPANT

Similar to the casing of names of properties, lower case parameters calculate the property, whereas upper case parameters directly access the iCalendar property.

>>> print(attendee.email)  # calculated
maxm@example.com
>>> print(attendee.CN)  # direct access
Max Rasmussen

The parameters turn up the iCal representation.

>>> event.attendees = [attendee]
>>> print(event.to_ical())
BEGIN:VEVENT
SUMMARY:New Year's Day Celebration
DTSTART;VALUE=DATE:20220101
DTSTAMP:20250517T080612Z
UID:d755cef5-2311-46ed-a0e1-6733c9e15c63
ATTENDEE;CN="Max Rasmussen";ROLE=REQ-PARTICIPANT:mailto:maxm@example.com
END:VEVENT

Dictionary access#

The lowest level is the dictionary interface. It is stable since version 4.0.

Although it's possible to directly set str values, it's preferred to use add() instead. As mentioned in Property access above, some properties won't get set or validated through this method.

>>> from icalendar import Calendar
>>> calendar = Calendar()  # create and empty calendar
>>> calendar.add("prodid", "-//My calendar product//mxm.dk//")
>>> calendar.add("version", "2.0")
>>> print(calendar.to_ical())
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My calendar product//mxm.dk//
END:VCALENDAR

The component is a dictionary, so you can access properties by key. All keys are case insensitive. This is implemented in CaselessDict.

>>> calendar["version"] == calendar["VERSION"]
True

The values can be retrieved by using get(). The values are encoded as property values specified in icalendar.prop.

>>> calendar.get("version")
vText(b'2.0')
>>> print(calendar.get("name"))
None

Parameter dictionary#

All property values are defined in icalendar.prop and have parameters. vText is used for VERSION, PRODID, and DESCRIPTION. Preferably, use the Parameter properties to get and set the values. You can also access them using .params.

The following example sets the DESCRIPTION from RFC 7986 Section 5.1, and adds a LANGUAGE parameter:

>>> from icalendar import vText
>>> description = vText("This is my personal calendar.")
>>> description.params["language"] = "en"  # set language to English
>>> calendar["description"] = description
>>> print(calendar.to_ical())
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//My calendar product//mxm.dk//
DESCRIPTION;LANGUAGE=en:This is my personal calendar.
END:VCALENDAR