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 32from pydantic import Field, field_serializer 33 34from .calendar import Calendar 35from .component import ComponentModel 36from .parsing.component import encode_content, parse_content 37from .types.data_types import serialize_field 38from .exceptions import CalendarParseError 39from pydantic import ConfigDict 40 41_LOGGER = logging.getLogger(__name__) 42 43 44class CalendarStream(ComponentModel): 45 """A container that is a collection of calendaring information. 46 47 This object supports parsing an rfc5545 calendar file, but does not 48 support encoding. See `IcsCalendarStream` instead for encoding ics files. 49 """ 50 51 calendars: list[Calendar] = Field(alias="vcalendar", default_factory=list) 52 53 @classmethod 54 def from_ics(cls, content: str) -> "CalendarStream": 55 """Factory method to create a new instance from an rfc5545 iCalendar content.""" 56 components = parse_content(content) 57 result: dict[str, list] = {"vcalendar": []} 58 for component in components: 59 result.setdefault(component.name, []) 60 result[component.name].append(component.as_dict()) 61 _LOGGER.debug("Parsing object %s", result) 62 return cls(**result) 63 64 def ics(self) -> str: 65 """Encode the calendar stream as an rfc5545 iCalendar Stream content.""" 66 return encode_content(self.__encode_component_root__().components) 67 68 69class IcsCalendarStream(CalendarStream): 70 """A calendar stream that supports parsing and encoding ICS.""" 71 72 @classmethod 73 def calendar_from_ics(cls, content: str) -> Calendar: 74 """Load a single calendar from an ics string.""" 75 stream = cls.from_ics(content) 76 if len(stream.calendars) == 1: 77 return stream.calendars[0] 78 if len(stream.calendars) == 0: 79 return Calendar() 80 raise CalendarParseError("Calendar Stream had more than one calendar") 81 82 @classmethod 83 def calendar_to_ics(cls, calendar: Calendar) -> str: 84 """Serialize a calendar as an ICS stream.""" 85 stream = cls(vcalendar=[calendar]) 86 return stream.ics() 87 88 model_config = ConfigDict( 89 validate_assignment=True, 90 populate_by_name=True, 91 ) 92 serialize_fields = field_serializer("*")(serialize_field) # type: ignore[pydantic-field]
class
CalendarStream(ical.component.ComponentModel):
45class CalendarStream(ComponentModel): 46 """A container that is a collection of calendaring information. 47 48 This object supports parsing an rfc5545 calendar file, but does not 49 support encoding. See `IcsCalendarStream` instead for encoding ics files. 50 """ 51 52 calendars: list[Calendar] = Field(alias="vcalendar", default_factory=list) 53 54 @classmethod 55 def from_ics(cls, content: str) -> "CalendarStream": 56 """Factory method to create a new instance from an rfc5545 iCalendar content.""" 57 components = parse_content(content) 58 result: dict[str, list] = {"vcalendar": []} 59 for component in components: 60 result.setdefault(component.name, []) 61 result[component.name].append(component.as_dict()) 62 _LOGGER.debug("Parsing object %s", result) 63 return cls(**result) 64 65 def ics(self) -> str: 66 """Encode the calendar stream as an rfc5545 iCalendar Stream content.""" 67 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]
54 @classmethod 55 def from_ics(cls, content: str) -> "CalendarStream": 56 """Factory method to create a new instance from an rfc5545 iCalendar content.""" 57 components = parse_content(content) 58 result: dict[str, list] = {"vcalendar": []} 59 for component in components: 60 result.setdefault(component.name, []) 61 result[component.name].append(component.as_dict()) 62 _LOGGER.debug("Parsing object %s", result) 63 return cls(**result)
Factory method to create a new instance from an rfc5545 iCalendar content.
70class IcsCalendarStream(CalendarStream): 71 """A calendar stream that supports parsing and encoding ICS.""" 72 73 @classmethod 74 def calendar_from_ics(cls, content: str) -> Calendar: 75 """Load a single calendar from an ics string.""" 76 stream = cls.from_ics(content) 77 if len(stream.calendars) == 1: 78 return stream.calendars[0] 79 if len(stream.calendars) == 0: 80 return Calendar() 81 raise CalendarParseError("Calendar Stream had more than one calendar") 82 83 @classmethod 84 def calendar_to_ics(cls, calendar: Calendar) -> str: 85 """Serialize a calendar as an ICS stream.""" 86 stream = cls(vcalendar=[calendar]) 87 return stream.ics() 88 89 model_config = ConfigDict( 90 validate_assignment=True, 91 populate_by_name=True, 92 ) 93 serialize_fields = field_serializer("*")(serialize_field) # type: ignore[pydantic-field]
A calendar stream that supports parsing and encoding ICS.
73 @classmethod 74 def calendar_from_ics(cls, content: str) -> Calendar: 75 """Load a single calendar from an ics string.""" 76 stream = cls.from_ics(content) 77 if len(stream.calendars) == 1: 78 return stream.calendars[0] 79 if len(stream.calendars) == 0: 80 return Calendar() 81 raise CalendarParseError("Calendar Stream had more than one calendar")
Load a single calendar from an ics string.
83 @classmethod 84 def calendar_to_ics(cls, calendar: Calendar) -> str: 85 """Serialize a calendar as an ICS stream.""" 86 stream = cls(vcalendar=[calendar]) 87 return stream.ics()
Serialize a calendar as an ICS stream.
model_config =
{'validate_assignment': True, 'populate_by_name': True, 'arbitrary_types_allowed': True, 'validate_by_alias': True, 'validate_by_name': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
def
serialize_fields( self: pydantic.main.BaseModel, value: Any, info: pydantic_core.core_schema.SerializationInfo) -> Any:
171def serialize_field(self: BaseModel, value: Any, info: SerializationInfo) -> Any: 172 if not info.context or not info.context.get("ics"): 173 return value 174 if isinstance(value, list): 175 res = [] 176 for val in value: 177 for base in val.__class__.__mro__[:-1]: 178 if (func := DATA_TYPE.encode_property_json.get(base)) is not None: 179 res.append(func(val)) 180 break 181 else: 182 res.append(val) 183 return res 184 185 for base in value.__class__.__mro__[:-1]: 186 if (func := DATA_TYPE.encode_property_json.get(base)) is not None: 187 return func(value) 188 return value