def serialize(self, component: Component, output: Container, context: ContextDict): value = self.get_value(component) if not TYPE_CHECKING: assert isinstance(value, dateutil.rrule.rruleset) for rrule in itertools.chain(value._rrule, value._exrule): if rrule._dtstart is None: continue # check that the rrule uses the same DTSTART as a possible Timespan(Converter) dtstart = context["DTSTART"] if dtstart: if dtstart != rrule._dtstart: raise ValueError("differing DTSTART values") else: context["DTSTART"] = rrule._dtstart dt_value = DatetimeConverter.serialize(rrule._dtstart, context=context) output.append(ContentLine(name="DTSTART", value=dt_value)) for rrule in value._rrule: output.append(rrule_to_ContentLine(rrule)) for exrule in value._exrule: cl = rrule_to_ContentLine(exrule) cl.name = "EXRULE" output.append(cl) for rdate in unique_justseen(sorted(value._rdate)): output.append( ContentLine(name="RDATE", value=DatetimeConverter.serialize(rdate))) for exdate in unique_justseen(sorted(value._exdate)): output.append( ContentLine(name="EXDATE", value=DatetimeConverter.serialize(exdate)))
def serialize(self, component: Component, output: Container, context: ContextDict): value: Timespan = self.get_value(component) dt_conv: ValueConverter if value.is_all_day(): value_type = {"VALUE": ["DATE"]} dt_conv = DateConverter else: value_type = {} # implicit default is {"VALUE": ["DATE-TIME"]} dt_conv = DatetimeConverter if value.get_begin(): # prevent rrule serializer from adding its own DTSTART value assert "DTSTART" not in context context["DTSTART"] = value.get_begin() params = copy_extra_params( cast(ExtraParams, self.get_extra_params(component, "begin"))) params.update(value_type) dt_value = dt_conv.serialize(value.get_begin(), params, context) output.append( ContentLine(name="DTSTART", params=params, value=dt_value)) if value.get_end_representation() == "end": end_name = {"end": "DTEND", "due": "DUE"}[value._end_name()] params = copy_extra_params( cast(ExtraParams, self.get_extra_params(component, end_name))) params.update(value_type) dt_value = dt_conv.serialize(value.get_effective_end(), params, context) output.append( ContentLine(name=end_name, params=params, value=dt_value)) elif value.get_end_representation() == "duration": params = copy_extra_params( cast(ExtraParams, self.get_extra_params(component, "duration"))) duration = value.get_effective_duration() assert duration is not None dur_value = DurationConverter.serialize(duration, params, context) output.append( ContentLine(name="DURATION", params=params, value=dur_value))
def test_any_text_value_recode(value): esc = TextConv.serialize(value) assert TextConv.parse(esc) == value cl = ContentLine("TEST", value=esc) assert parse_contentline(cl.serialize()) == cl assert list(string_to_containers(cl.serialize())) == [cl] vals = [esc, esc, "test", esc] cl2 = ContentLine("TEST", value=TextConv.join_value_list(vals)) assert list(TextConv.split_value_list(cl2.value)) == vals assert parse_contentline(cl.serialize()) == cl assert list(string_to_containers(cl.serialize())) == [cl]
def serialize(self, component: "Component", output: Container, context: ContextDict): if self.is_multi_value: self.__serialize_multi(component, output, context) else: value = self.get_value(component) if value: params = copy_extra_params( cast(ExtraParams, self.get_extra_params(component))) converter = self.__find_value_converter(params, value) serialized = converter.serialize(value, params, context) output.append( ContentLine(name=self.ics_name, params=params, value=serialized))
def serialize(self, component: "Component", output: Container, context: ContextDict): value: Timespan = self.get_value(component) if value.is_all_day(): value_type = {"VALUE": ["DATE"]} dt_conv = DateConverter.INST else: value_type = {} # implicit default is {"VALUE": ["DATE-TIME"]} dt_conv = DatetimeConverter.INST if value.get_begin(): params = copy_extra_params( cast(ExtraParams, self.get_extra_params(component, "begin"))) params.update(value_type) dt_value = dt_conv.serialize(value.get_begin(), params, context) output.append( ContentLine(name="DTSTART", params=params, value=dt_value)) if value.get_end_representation() == "end": end_name = {"end": "DTEND", "due": "DUE"}[value._end_name()] params = copy_extra_params( cast(ExtraParams, self.get_extra_params(component, end_name))) params.update(value_type) dt_value = dt_conv.serialize(value.get_effective_end(), params, context) output.append( ContentLine(name=end_name, params=params, value=dt_value)) elif value.get_end_representation() == "duration": params = copy_extra_params( cast(ExtraParams, self.get_extra_params(component, "duration"))) dur_value = DurationConverter.INST.serialize( value.get_effective_duration(), params, context) output.append( ContentLine(name="DURATION", params=params, value=dur_value))
def __serialize_multi(self, component: Component, output: Container, context: ContextDict): extra_params = cast(List[ExtraParams], self.get_extra_params(component)) values = self.get_value_list(component) if not extra_params: extra_params = repeat(None) elif len(extra_params) != len(values): raise ValueError( "length of extra params doesn't match length of parameters" " for attribute %s of %r" % (self.attribute.name, component)) merge_next = False current_params = None current_values = [] for value, params in zip(values, extra_params): merge_next = False params = copy_extra_params(params) if params.pop("__merge_next", None) == ["TRUE"]: merge_next = True converter = self.__find_value_converter(params, value) serialized = converter.serialize( value, params, context) # might modify params and context if current_params is not None: if current_params != params: raise ValueError() else: current_params = params current_values.append(serialized) if not merge_next: cl = ContentLine( name=self.ics_name, params=params, value=converter.join_value_list(current_values)) output.append(cl) current_params = None current_values = [] if merge_next: raise ValueError( "last value in value list may not have merge_next set")
def test_issue_182_seconds_ignored(): todo = Todo.from_container( lines_to_container([ "BEGIN:VTODO", "DTSTART;TZID=Europe/Berlin:20180219T120005", "COMPLETED;TZID=Europe/Brussels:20180418T150001", "END:VTODO" ])) assert todo.begin == datetime(2018, 2, 19, 12, 0, 5, tzinfo=gettz("Europe/Berlin")) assert todo.completed == datetime(2018, 4, 18, 15, 0, 1, tzinfo=gettz("Europe/Brussels")) with pytest.raises(ValueError): Todo.from_container( lines_to_container([ "BEGIN:VTODO", "DTSTART;TZID=Europe/Berlin:2018-02-19 12:00:05", "END:VTODO" ])) container = lines_to_container([ "BEGIN:VTODO", "COMPLETED:;TZID=Europe/Brussels:20180418T150001", # ^ this : breaks parsing "END:VTODO" ]) assert container[0] == ContentLine( "COMPLETED", value=";TZID=Europe/Brussels:20180418T150001") pytest.raises(ValueError, Todo.from_container, container)
from ics.valuetype.text import TextConverter # Text may be comma-separated multi-value but is never quoted, with the characters [\\;,\n] escaped from tests.contentline import VALUE TextConv: TextConverter = TextConverter.INST def parse_contentline(line: str) -> ContentLine: cl, = Parser.lines_to_contentlines(Parser.string_to_lines(line)) return cl @pytest.mark.parametrize("inp_esc, out_uesc", [ ("SUMMARY:Project XYZ Final Review\\nConference Room - 3B\\nCome Prepared.", ContentLine( "SUMMARY", value="Project XYZ Final Review\nConference Room - 3B\nCome Prepared." )), ("DESCRIPTION;ALTREP=\"cid:[email protected]\":The Fall'98 Wild Wizards Conference - - Las Vegas\\, NV\\, USA", ContentLine( "DESCRIPTION", {"ALTREP": ["cid:[email protected]"]}, value="The Fall'98 Wild Wizards Conference - - Las Vegas, NV, USA")), ("TEST:abc\\r\\n\\,\\;:\"\t=xyz", ContentLine("TEST", value="abc\r\n,;:\"\t=xyz")), ]) def test_example_text_recode(inp_esc, out_uesc): par_esc = parse_contentline(inp_esc) par_uesc = attr.evolve(par_esc, value=TextConv.parse(par_esc.value)) out_esc = attr.evolve(out_uesc, value=TextConv.serialize(out_uesc.value)) assert par_uesc == out_uesc ser_esc = out_esc.serialize() assert inp_esc == ser_esc
def serialize(self, component: Component, output: Container, context: ContextDict): output.append( ContentLine(name="ACTION", params=component.extra_params.get("ACTION", {}), value=component.action))