ical.calendar_stream

The core, a collection of Calendar and Scheduling objects.

This is an example of parsing an ics file as a stream of calendar objects:

from pathlib import Path
from ical.calendar_stream import IcsCalendarStream

filename = Path("example/calendar.ics")
with filename.open() as ics_file:
    stream = IcsCalendarStream.from_ics(ics_file.read())
    print("File contains %s calendar(s)", len(stream.calendars))

You can encode a calendar stream as ics content calling the ics() method on the IcsCalendarStream:

from pathlib import Path

filename = Path("/tmp/output.ics")
with filename.open(mode="w") as ics_file:
    ics_file.write(stream.ics())
  1"""The core, a collection of Calendar and Scheduling objects.
  2
  3This is an example of parsing an ics file as a stream of calendar objects:
  4```python
  5from pathlib import Path
  6from ical.calendar_stream import IcsCalendarStream
  7
  8filename = Path("example/calendar.ics")
  9with filename.open() as ics_file:
 10    stream = IcsCalendarStream.from_ics(ics_file.read())
 11    print("File contains %s calendar(s)", len(stream.calendars))
 12```
 13
 14You can encode a calendar stream as ics content calling the `ics()` method on
 15the `IcsCalendarStream`:
 16
 17```python
 18from pathlib import Path
 19
 20filename = Path("/tmp/output.ics")
 21with filename.open(mode="w") as ics_file:
 22    ics_file.write(stream.ics())
 23```
 24
 25"""
 26
 27# mypy: allow-any-generics
 28
 29from __future__ import annotations
 30
 31import logging
 32import pyparsing
 33
 34try:
 35    from pydantic.v1 import Field
 36except ImportError:
 37    from pydantic import Field  # type: ignore[assignment]
 38
 39from .calendar import Calendar
 40from .component import ComponentModel
 41from .parsing.component import encode_content, parse_content
 42from .types.data_types import DATA_TYPE
 43from .exceptions import CalendarParseError
 44
 45_LOGGER = logging.getLogger(__name__)
 46
 47
 48class CalendarStream(ComponentModel):
 49    """A container that is a collection of calendaring information.
 50
 51    This object supports parsing an rfc5545 calendar file, but does not
 52    support encoding. See `IcsCalendarStream` instead for encoding ics files.
 53    """
 54
 55    calendars: list[Calendar] = Field(alias="vcalendar", default_factory=list)
 56
 57    @classmethod
 58    def from_ics(cls, content: str) -> "CalendarStream":
 59        """Factory method to create a new instance from an rfc5545 iCalendar content."""
 60        try:
 61            components = parse_content(content)
 62        except pyparsing.ParseException as err:
 63            raise CalendarParseError(
 64                f"Failed to parse calendar contents", detailed_error=str(err)
 65            ) from err
 66        result: dict[str, list] = {"vcalendar": []}
 67        for component in components:
 68            result.setdefault(component.name, [])
 69            result[component.name].append(component.as_dict())
 70        _LOGGER.debug("Parsing object %s", result)
 71        return cls(**result)
 72
 73    def ics(self) -> str:
 74        """Encode the calendar stream as an rfc5545 iCalendar Stream content."""
 75        return encode_content(self.__encode_component_root__().components)
 76
 77
 78class IcsCalendarStream(CalendarStream):
 79    """A calendar stream that supports parsing and encoding ICS."""
 80
 81    @classmethod
 82    def calendar_from_ics(cls, content: str) -> Calendar:
 83        """Load a single calendar from an ics string."""
 84        stream = cls.from_ics(content)
 85        if len(stream.calendars) == 1:
 86            return stream.calendars[0]
 87        if len(stream.calendars) == 0:
 88            return Calendar()
 89        raise CalendarParseError("Calendar Stream had more than one calendar")
 90
 91    @classmethod
 92    def calendar_to_ics(cls, calendar: Calendar) -> str:
 93        """Serialize a calendar as an ICS stream."""
 94        stream = cls(vcalendar=[calendar])
 95        return stream.ics()
 96
 97    class Config:
 98        """Configuration for IcsCalendarStream pydantic model."""
 99
100        json_encoders = DATA_TYPE.encode_property_json
101        validate_assignment = True
102        allow_population_by_field_name = True
class CalendarStream(ical.component.ComponentModel):
49class CalendarStream(ComponentModel):
50    """A container that is a collection of calendaring information.
51
52    This object supports parsing an rfc5545 calendar file, but does not
53    support encoding. See `IcsCalendarStream` instead for encoding ics files.
54    """
55
56    calendars: list[Calendar] = Field(alias="vcalendar", default_factory=list)
57
58    @classmethod
59    def from_ics(cls, content: str) -> "CalendarStream":
60        """Factory method to create a new instance from an rfc5545 iCalendar content."""
61        try:
62            components = parse_content(content)
63        except pyparsing.ParseException as err:
64            raise CalendarParseError(
65                f"Failed to parse calendar contents", detailed_error=str(err)
66            ) from err
67        result: dict[str, list] = {"vcalendar": []}
68        for component in components:
69            result.setdefault(component.name, [])
70            result[component.name].append(component.as_dict())
71        _LOGGER.debug("Parsing object %s", result)
72        return cls(**result)
73
74    def ics(self) -> str:
75        """Encode the calendar stream as an rfc5545 iCalendar Stream content."""
76        return encode_content(self.__encode_component_root__().components)

A container that is a collection of calendaring information.

This object supports parsing an rfc5545 calendar file, but does not support encoding. See IcsCalendarStream instead for encoding ics files.

calendars: list[ical.calendar.Calendar]
@classmethod
def from_ics(cls, content: str) -> CalendarStream:
58    @classmethod
59    def from_ics(cls, content: str) -> "CalendarStream":
60        """Factory method to create a new instance from an rfc5545 iCalendar content."""
61        try:
62            components = parse_content(content)
63        except pyparsing.ParseException as err:
64            raise CalendarParseError(
65                f"Failed to parse calendar contents", detailed_error=str(err)
66            ) from err
67        result: dict[str, list] = {"vcalendar": []}
68        for component in components:
69            result.setdefault(component.name, [])
70            result[component.name].append(component.as_dict())
71        _LOGGER.debug("Parsing object %s", result)
72        return cls(**result)

Factory method to create a new instance from an rfc5545 iCalendar content.

def ics(self) -> str:
74    def ics(self) -> str:
75        """Encode the calendar stream as an rfc5545 iCalendar Stream content."""
76        return encode_content(self.__encode_component_root__().components)

Encode the calendar stream as an rfc5545 iCalendar Stream content.

class IcsCalendarStream(CalendarStream):
 79class IcsCalendarStream(CalendarStream):
 80    """A calendar stream that supports parsing and encoding ICS."""
 81
 82    @classmethod
 83    def calendar_from_ics(cls, content: str) -> Calendar:
 84        """Load a single calendar from an ics string."""
 85        stream = cls.from_ics(content)
 86        if len(stream.calendars) == 1:
 87            return stream.calendars[0]
 88        if len(stream.calendars) == 0:
 89            return Calendar()
 90        raise CalendarParseError("Calendar Stream had more than one calendar")
 91
 92    @classmethod
 93    def calendar_to_ics(cls, calendar: Calendar) -> str:
 94        """Serialize a calendar as an ICS stream."""
 95        stream = cls(vcalendar=[calendar])
 96        return stream.ics()
 97
 98    class Config:
 99        """Configuration for IcsCalendarStream pydantic model."""
100
101        json_encoders = DATA_TYPE.encode_property_json
102        validate_assignment = True
103        allow_population_by_field_name = True

A calendar stream that supports parsing and encoding ICS.

@classmethod
def calendar_from_ics(cls, content: str) -> ical.calendar.Calendar:
82    @classmethod
83    def calendar_from_ics(cls, content: str) -> Calendar:
84        """Load a single calendar from an ics string."""
85        stream = cls.from_ics(content)
86        if len(stream.calendars) == 1:
87            return stream.calendars[0]
88        if len(stream.calendars) == 0:
89            return Calendar()
90        raise CalendarParseError("Calendar Stream had more than one calendar")

Load a single calendar from an ics string.

@classmethod
def calendar_to_ics(cls, calendar: ical.calendar.Calendar) -> str:
92    @classmethod
93    def calendar_to_ics(cls, calendar: Calendar) -> str:
94        """Serialize a calendar as an ICS stream."""
95        stream = cls(vcalendar=[calendar])
96        return stream.ics()

Serialize a calendar as an ICS stream.

Inherited Members
CalendarStream
calendars
from_ics
ics
class IcsCalendarStream.Config:
 98    class Config:
 99        """Configuration for IcsCalendarStream pydantic model."""
100
101        json_encoders = DATA_TYPE.encode_property_json
102        validate_assignment = True
103        allow_population_by_field_name = True

Configuration for IcsCalendarStream pydantic model.

json_encoders = {<class 'datetime.date'>: <bound method DateEncoder.__encode_property_json__ of <class 'ical.types.date.DateEncoder'>>, <class 'datetime.datetime'>: <bound method DateTimeEncoder.__encode_property_json__ of <class 'ical.types.date_time.DateTimeEncoder'>>, <class 'datetime.timedelta'>: <bound method DurationEncoder.__encode_property_json__ of <class 'ical.types.duration.DurationEncoder'>>, <class 'ical.types.Geo'>: <bound method Geo.__encode_property_json__ of <class 'ical.types.Geo'>>, <class 'ical.types.RequestStatus'>: <bound method RequestStatus.__encode_property_json__ of <class 'ical.types.RequestStatus'>>, <class 'ical.types.UtcOffset'>: <bound method UtcOffset.__encode_property_json__ of <class 'ical.types.UtcOffset'>>}
validate_assignment = True
allow_population_by_field_name = True