def test_container_parse_error(): pytest.raises(ParseError, string_to_container, "BEGIN:TEST") assert string_to_container("END:TEST") == [ContentLine(name="END", value="TEST")] pytest.raises(ParseError, string_to_container, "BEGIN:TEST1\nEND:TEST2") pytest.raises(ParseError, string_to_container, "BEGIN:TEST1\nEND:TEST2\nEND:TEST1") assert string_to_container("BEGIN:TEST1\nEND:TEST1\nEND:TEST1") == [Container("TEST1"), ContentLine(name="END", value="TEST1")] pytest.raises(ParseError, string_to_container, "BEGIN:TEST1\nBEGIN:TEST1\nEND:TEST1")
def test_any_text_value_recode(value): esc = TextConv.serialize(value) assert TextConv.parse(esc) == value cl = ContentLine("TEST", value=esc) assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(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 ContentLine.parse(cl.serialize()) == cl assert string_to_container(cl.serialize()) == [cl]
def test_container(): inp = """BEGIN:TEST VAL1:The-Val VAL2;PARAM1=P1;PARAM2=P2A,P2B;PARAM3="P3:A","P3:B,C":The-Val2 END:TEST""" out = Container('TEST', [ ContentLine(name='VAL1', params={}, value='The-Val'), ContentLine(name='VAL2', params={'PARAM1': ['P1'], 'PARAM2': ['P2A', 'P2B'], 'PARAM3': ['P3:A', 'P3:B,C']}, value='The-Val2')]) assert string_to_container(inp) == [out] assert out.serialize() == inp.replace("\n", "\r\n") assert str(out) == "TEST[VAL1='The-Val', VAL2{'PARAM1': ['P1'], 'PARAM2': ['P2A', 'P2B'], 'PARAM3': ['P3:A', 'P3:B,C']}='The-Val2']" assert repr(out) == "Container('TEST', [ContentLine(name='VAL1', params={}, value='The-Val'), ContentLine(name='VAL2', params={'PARAM1': ['P1'], 'PARAM2': ['P2A', 'P2B'], 'PARAM3': ['P3:A', 'P3:B,C']}, value='The-Val2')])" out_shallow = out.clone(deep=False) out_deep = out.clone(deep=True) assert out == out_shallow == out_deep assert all(a == b for a, b in zip(out, out_shallow)) assert all(a == b for a, b in zip(out, out_deep)) assert all(a is b for a, b in zip(out, out_shallow)) assert all(a is not b for a, b in zip(out, out_deep)) out_deep.append(ContentLine("LAST")) assert out != out_deep out[0].params["NEW"] = "SOMETHING" assert out == out_shallow out_shallow.name = "DIFFERENT" assert out != out_shallow with pytest.raises(TypeError): out_shallow[0] = ['CONTENT:Line'] with pytest.raises(TypeError): out_shallow[:] = ['CONTENT:Line'] pytest.raises(TypeError, out_shallow.append, 'CONTENT:Line') pytest.raises(TypeError, out_shallow.append, ['CONTENT:Line']) pytest.raises(TypeError, out_shallow.extend, ['CONTENT:Line']) out_shallow[:] = [out[0]] assert out_shallow == Container("DIFFERENT", [out[0]]) out_shallow[:] = [] assert out_shallow == Container("DIFFERENT") out_shallow.append(ContentLine("CL1")) out_shallow.extend([ContentLine("CL3")]) out_shallow.insert(1, ContentLine("CL2")) out_shallow += [ContentLine("CL4")] assert out_shallow[1:3] == Container("DIFFERENT", [ContentLine("CL2"), ContentLine("CL3")]) assert out_shallow == Container("DIFFERENT", [ContentLine("CL1"), ContentLine("CL2"), ContentLine("CL3"), ContentLine("CL4")]) with pytest.warns(UserWarning, match="not all-uppercase"): assert string_to_container("BEGIN:test\nEND:TeSt") == [Container("TEST", [])]
def test_container_nested(): inp = """BEGIN:TEST1 VAL1:The-Val BEGIN:TEST2 VAL2:The-Val BEGIN:TEST3 VAL3:The-Val END:TEST3 END:TEST2 VAL4:The-Val BEGIN:TEST2 VAL5:The-Val END:TEST2 BEGIN:TEST2 VAL5:The-Val END:TEST2 VAL6:The-Val END:TEST1""" out = Container('TEST1', [ ContentLine(name='VAL1', params={}, value='The-Val'), Container('TEST2', [ ContentLine(name='VAL2', params={}, value='The-Val'), Container('TEST3', [ ContentLine(name='VAL3', params={}, value='The-Val') ]) ]), ContentLine(name='VAL4', params={}, value='The-Val'), Container('TEST2', [ ContentLine(name='VAL5', params={}, value='The-Val')]), Container('TEST2', [ ContentLine(name='VAL5', params={}, value='The-Val')]), ContentLine(name='VAL6', params={}, value='The-Val')]) assert string_to_container(inp) == [out] assert out.serialize() == inp.replace("\n", "\r\n")
def parse_multiple(cls, string): """" Parses an input string that may contain mutiple calendars and retruns a list of :class:`ics.event.Calendar` """ containers = string_to_container(string) return [cls(imports=c) for c in containers]
def __init__(self, imports: Union[str, Container, None] = None, events: Optional[Iterable[Event]] = None, todos: Optional[Iterable[Todo]] = None, creator: str = None, **kwargs): """Initializes a new Calendar. Args: imports (**str**): data to be imported into the Calendar, events (**Iterable[Event]**): `Event`s to be added to the calendar todos (**Iterable[Todo]**): `Todo`s to be added to the calendar creator (**string**): uid of the creator program. """ if events is None: events = tuple() if todos is None: todos = tuple() kwargs.setdefault("version", self.DEFAULT_VERSION) kwargs.setdefault( "prodid", creator if creator is not None else self.DEFAULT_PRODID) super(Calendar, self).__init__(events=events, todos=todos, **kwargs) # type: ignore self.timeline = Timeline(self, None) if imports is not None: if isinstance(imports, Container): self.populate(imports) else: containers = string_to_container(imports) if len(containers) != 1: raise ValueError( "Multiple calendars in one file are not supported by this method." "Use ics.Calendar.parse_multiple()") self.populate(containers[0])
def test_any_name_params_value_recode(name, value, param1, p1value, param2, p2value1, p2value2): assume(param1 != param2) raw = "%s;%s=%s;%s=%s,%s:%s" % (name, param1, quote_escape_param(p1value), param2, quote_escape_param(p2value1), quote_escape_param(p2value2), value) assert ContentLine.parse(raw).serialize() == raw cl = ContentLine(name, {param1: [p1value], param2: [p2value1, p2value2]}, value) assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(raw) == [cl]
def test_example_text_recode(inp_esc, out_uesc): par_esc = ContentLine.parse(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 assert string_to_container(inp_esc) == [par_esc]
def test_example_recode(inp, out): par = ContentLine.parse(inp) assert par == out ser = out.serialize() if inp[0].isupper(): assert inp == ser else: assert inp.upper() == ser.upper() par_ser = par.serialize() if inp[0].isupper(): assert inp == par_ser else: assert inp.upper() == par_ser.upper() assert string_to_container(inp) == [out]
def test_value_characters(): chars = "abcABC0123456789" "-=_+!$%&*()[]{}<>'@#~/?|`¬€¨ÄÄää´ÁÁááßæÆ \t\\n😜🇪🇺👩🏾💻👨🏻👩🏻👧🏻👦🏻xyzXYZ" special_chars = ";:,\"^" inp = "TEST;P1={chars};P2={chars},{chars},\"{chars}\",{chars}:{chars}:{chars}{special}".format( chars=chars, special=special_chars) out = ContentLine("TEST", {"P1": [chars], "P2": [chars, chars, QuotedParamValue(chars), chars]}, chars + ":" + chars + special_chars) par = ContentLine.parse(inp) assert par == out ser = out.serialize() assert inp == ser par_ser = par.serialize() assert inp == par_ser assert string_to_container(inp) == [out]
def test_param_quoting(): inp = 'TEST;P1="A";P2=B;P3=C,"D",E,"F":"VAL"' out = ContentLine("TEST", { "P1": [QuotedParamValue("A")], "P2": ["B"], "P3": ["C", QuotedParamValue("D"), "E", QuotedParamValue("F")], }, '"VAL"') par = ContentLine.parse(inp) assert par == out ser = out.serialize() assert inp == ser par_ser = par.serialize() assert inp == par_ser assert string_to_container(inp) == [out] for param in out.params.keys(): for o_val, p_val in zip(out[param], par[param]): assert type(o_val) == type(p_val)
def test_unfold(): val1 = "DESCRIPTION:This is a long description that exists on a long line." val2 = "DESCRIPTION:This is a lo\n ng description\n that exists on a long line." assert "".join(unfold_lines(val2.splitlines())) == val1 assert string_to_container(val1) == string_to_container(val2) == [ContentLine.parse(val1)] pytest.raises(ValueError, ContentLine.parse, val2)
def test_any_param_value_recode(param, value): raw = "TEST;%s=%s:VALUE" % (param, quote_escape_param(value)) assert ContentLine.parse(raw).serialize() == raw cl = ContentLine("TEST", {param: [value]}, "VALUE") assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(raw) == [cl]
def test_any_name_value_recode(name, value): raw = "%s:%s" % (name, value) assert ContentLine.parse(raw).serialize() == raw cl = ContentLine(name, value=value) assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(raw) == [cl]
def read_tz(path): with open(path, "rt") as f: ics_cal = string_to_container(f.read()) if not (len(ics_cal) == 1 and len(ics_cal[0]) == 3 and ics_cal[0][2].name == "VTIMEZONE"): raise ValueError("vTimezone.ics file %s has invalid content" % path) return Timezone.from_container(ics_cal[0][2])