ics-py / ics-py

Pythonic and easy iCalendar library (rfc5545)

Home Page:http://icspy.readthedocs.org/en/stable/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot write ics file (unstable version)

Skillkiller opened this issue · comments

Hello,
I am trying to read in an ICS file and then write the calendar object back into an ICS file. Unfortunately, writing to a file does not work properly. When writing to the file, new lines are always written in between, which makes the ICS file no longer validly formatted.

I use the new version from the main use. Here is an excerpt on pip freeze:

pip freeze | grep ics
ics @ git+https://github.com/ics-py/ics-py.git@507cd15a42997178f18b08fa8255e208345c37ee
ics-vtimezones==2020.1

Here the example code:

from ics import Calendar

with open("Input.ics", "r") as file1:
    l = file1.read()
c = Calendar(l)

print(c.serialize())
print(c)

with open("Output.ics", 'w') as output_file:
    output_file.writelines(c.serialize())

Input.ics:

BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
PRODID:-//schulferien.org//iCal Generator//DE
BEGIN:VEVENT
CREATED:20230630T032002Z
LAST-MODIFIED:20230630T032002Z
DTSTAMP:20230630T032002Z
SUMMARY:Neujahr
DTSTART;VALUE=DATE:20240101
DTEND;VALUE=DATE:20240102
URL:http://www.schulferien.org
DESCRIPTION:Alle Termine auf www.schulferien.org
TRANSP:TRANSPARENT
UID:FT_2024_feiertag649e2dc4b1032@schulferien.org
END:VEVENT
END:VCALENDAR

Output.ics:

BEGIN:VCALENDAR

VERSION:2.0

PRODID:-//schulferien.org//iCal Generator//DE

METHOD:PUBLISH

BEGIN:VEVENT

DTSTART;VALUE=DATE:20240101

DTEND;VALUE=DATE:20240102

SUMMARY:Neujahr

UID:FT_2024_feiertag649e2dc4b1032@schulferien.org

DESCRIPTION:Alle Termine auf www.schulferien.org

URL:http://www.schulferien.org

CREATED:20230630T032002Z

LAST-MODIFIED:20230630T032002Z

DTSTAMP:20230630T032002Z

TRANSP:TRANSPARENT

END:VEVENT

END:VCALENDAR

Console:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//schulferien.org//iCal Generator//DE
METHOD:PUBLISH
BEGIN:VEVENT
DTSTART;VALUE=DATE:20240101
DTEND;VALUE=DATE:20240102
SUMMARY:Neujahr
UID:FT_2024_feiertag649e2dc4b1032@schulferien.org
DESCRIPTION:Alle Termine auf www.schulferien.org
URL:http://www.schulferien.org
CREATED:20230630T032002Z
LAST-MODIFIED:20230630T032002Z
DTSTAMP:20230630T032002Z
TRANSP:TRANSPARENT
END:VEVENT
END:VCALENDAR
<Calendar with 1 event and 0 todos>

c.serialize() yields a single str, so you should simply do output_file.write(c.serialize()). There is also a slightly more efficient c.to_container().serialize_iter() which yields multiple strings (instead of assembling the string in memory first) for use with writelines, although it will usually yield more than one string per line and instead includes "\r\n" at the right places. This is no problem though, as writelines should add no own line separators.

I guess the problem here is with python's universal newline mode in combination with how your OS handles newlines. The ics standard mandates \r\n as line separator, and we follow this requirement. On your system, this might then be mangled into two separated \ns. Could you try open(..., newline="") or one of its documented variants?

Hint: use repr to get more insights into the line separators present in a string:

>>> print(repr(list(c.to_container().serialize_iter()))) # out.writelines(c.to_container().serialize_iter())
['BEGIN:', 'VCALENDAR', '\r\n', 'VERSION:2.0', '\r\n', 'PRODID:-//schulferien.org//iCal Generator//DE', '\r\n', 'METHOD:PUBLISH', '\r\n', 'BEGIN:', 'VEVENT', '\r\n', 'DTSTART;VALUE=DATE:20240101', '\r\n', 'DTEND;VALUE=DATE:20240102', '\r\n', 'SUMMARY:Neujahr', '\r\n', 'UID:FT_2024_feiertag649e2dc4b1032@schulferien.org', '\r\n', 'DESCRIPTION:Alle Termine auf www.schulferien.org', '\r\n', 'URL:http://www.schulferien.org', '\r\n', 'CREATED:20230630T032002Z', '\r\n', 'LAST-MODIFIED:20230630T032002Z', '\r\n', 'DTSTAMP:20230630T032002Z', '\r\n', 'TRANSP:TRANSPARENT', '\r\n', 'END:', 'VEVENT', '\r\n', 'END:', 'VCALENDAR']
>>> print(repr(c.serialize())) # out.write(c.serialize())
'BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//schulferien.org//iCal Generator//DE\r\nMETHOD:PUBLISH\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20240101\r\nDTEND;VALUE=DATE:20240102\r\nSUMMARY:Neujahr\r\nUID:FT_2024_feiertag649e2dc4b1032@schulferien.org\r\nDESCRIPTION:Alle Termine auf www.schulferien.org\r\nURL:http://www.schulferien.org\r\nCREATED:20230630T032002Z\r\nLAST-MODIFIED:20230630T032002Z\r\nDTSTAMP:20230630T032002Z\r\nTRANSP:TRANSPARENT\r\nEND:VEVENT\r\nEND:VCALENDAR'

Thank you for your answer. open(..., newline="") has solved the problem. Both with output_file.writelines(c.serialise()) and with output_file.writelines(c.to_container().serialise_iter()).

Thank you for the help.