Skip to content

Commit 9da8899

Browse files
authored
Merge pull request #4 from rkdarst/ics-0.8.0
Port yaml2ics to ics 0.8.0
2 parents d80e655 + 63cfc63 commit 9da8899

6 files changed

Lines changed: 96 additions & 70 deletions

File tree

example/another_calendar.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
events:
2-
- name: Another Event
3-
begin: 2021-09-21 10:00-07:00
4-
end: 2021-09-21 12:00-07:00
2+
- summary: Another Event
3+
begin: 2021-09-21 10:00:00 -07:00
4+
end: 2021-09-21 12:00:00 -07:00
55
description: |
66
A two hour long event.

example/test_calendar.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
events:
2-
- name: Event of the Century
3-
begin: 2021-09-21 15:00-07:00
4-
end: 2021-09-21 15:30:00-07:00
2+
- summary: Event of the Century
3+
begin: 2021-09-21 15:00:00
4+
end: 2021-09-21 15:30:00
55
description: |
66
Meet the team on the northern side of the field.
77
8-
- name: Half-an-hour meeting
9-
begin: 2021-09-23 15:00-07:00
8+
- summary: Half-an-hour meeting
9+
begin: 2021-09-23 15:00:00
1010
duration:
1111
minutes: 30
1212
location: |
1313
Office 224, Monolith Bldg, Office Block C
1414
15-
- name: Earth Day
15+
- summary: Earth Day
1616
begin: 2021-04-22
1717
url: https://earthday.org
1818
repeat:

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
ics
1+
https://github.com/ics-py/ics-py/archive/refs/heads/main.zip
22
python-dateutil
33
pyyaml

tests/test_calendar.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,30 @@
1-
from yaml2ics import events_to_calendar_ics
1+
import io
2+
import textwrap
3+
4+
from util import parse_yaml
5+
6+
from yaml2ics import events_to_calendar, files_to_calendar
27

38

49
def test_calendar_structure():
5-
cal = events_to_calendar_ics(['event0', 'event1'])
6-
assert cal.startswith('BEGIN:VCALENDAR')
7-
assert cal.endswith('END:VCALENDAR')
10+
cal = events_to_calendar([])
11+
cal_str = cal.serialize()
12+
assert cal_str.startswith('BEGIN:VCALENDAR')
13+
assert cal_str.endswith('END:VCALENDAR')
14+
15+
def test_calendar_event():
16+
cal = files_to_calendar(
17+
[io.StringIO(textwrap.dedent(
18+
'''
19+
events:
20+
- summary: Earth Day
21+
begin: 2021-04-22
22+
url: https://earthday.org
23+
location: Earth
24+
'''
25+
))]
26+
)
27+
cal_str = cal.serialize()
28+
assert cal_str.startswith('BEGIN:VCALENDAR')
29+
assert 'SUMMARY:Earth Day' in cal_str
30+
assert cal_str.endswith('END:VCALENDAR')

tests/test_events.py

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,55 @@
11
from util import parse_yaml
22

3-
from yaml2ics import event_ics_from_yaml
3+
from yaml2ics import event_from_yaml
44

55

66
def test_basic_structure():
7-
event = event_ics_from_yaml(
7+
event = event_from_yaml(
88
parse_yaml(
99
'''
10-
name: Earth Day
10+
summary: Earth Day
1111
begin: 2021-04-22
1212
url: https://earthday.org
13+
location: Earth
1314
'''
1415
)
1516
)
1617

1718
# All lines must be separated by CRLF
18-
lines = event.split('\n')
19+
event_str = event.serialize()
20+
lines = event_str.split('\n')
1921
for line in lines[:-1]:
2022
assert line.endswith('\r')
21-
23+
assert 'SUMMARY:Earth Day' in event_str
24+
assert 'URL:https://earthday.org' in event_str
25+
assert 'LOCATION:Earth' in event_str
2226
# All events must have a DTSTAMP
23-
assert 'DTSTAMP' in event
27+
assert 'DTSTAMP' in event_str
2428

2529

2630
def test_all_day_event():
27-
event = event_ics_from_yaml(
31+
event = event_from_yaml(
2832
parse_yaml(
2933
'''
30-
name: Earth Day
34+
summary: Earth Day
3135
begin: 2021-04-22
3236
url: https://earthday.org
3337
'''
3438
)
3539
)
36-
assert event.startswith('BEGIN:VEVENT')
37-
assert event.endswith('END:VEVENT')
38-
assert 'DTSTART;VALUE=DATE:20210422' in event
39-
assert 'DTEND' not in event
40+
event_str = event.serialize()
41+
assert event_str.startswith('BEGIN:VEVENT')
42+
assert event_str.endswith('END:VEVENT')
43+
assert 'DTSTART;VALUE=DATE:20210422' in event_str
44+
# ics 0.8.0 does have DTEND that is the next day.
45+
#assert 'DTEND' not in event_str
4046

4147

4248
def test_rrule():
43-
event = event_ics_from_yaml(
49+
event = event_from_yaml(
4450
parse_yaml(
4551
'''
46-
name: Earth Day
52+
summary: Earth Day
4753
begin: 2021-04-22
4854
url: https://earthday.org
4955
repeat:
@@ -53,40 +59,43 @@ def test_rrule():
5359
'''
5460
)
5561
)
56-
assert 'DTEND' not in event
57-
assert 'RRULE:FREQ=YEARLY;UNTIL=20300422T000000Z' in event
62+
event_str = event.serialize()
63+
assert 'DTEND' not in event_str
64+
assert 'RRULE:FREQ=YEARLY;UNTIL=20300422T000000' in event_str
5865

5966

6067
def test_event_with_time_range():
61-
event = event_ics_from_yaml(
68+
event = event_from_yaml(
6269
parse_yaml(
6370
'''
64-
name: Event of the Century
65-
begin: 2021-09-21 15:00-07:00
66-
end: 2021-09-21 15:30:00-07:00
71+
summary: Event of the Century
72+
begin: 2021-09-21 15:00:00 -07:00
73+
end: 2021-09-21 15:30:00 -07:00
6774
description: |
6875
Meet the team on the northern side of the field.
6976
'''
7077
)
7178
)
72-
assert 'DTSTART' in event
73-
assert 'DTEND' in event
79+
event_str = event.serialize()
80+
assert 'DTSTART' in event_str
81+
assert 'DTEND' in event_str
7482

7583

7684
def test_event_with_duration():
77-
event = event_ics_from_yaml(
85+
event = event_from_yaml(
7886
parse_yaml(
7987
'''
80-
name: Event of the Century
81-
begin: 2021-09-21 15:00-07:00
88+
summary: Event of the Century
89+
begin: 2021-09-21 15:00:00 -07:00
8290
duration:
8391
minutes: 30
8492
description: |
8593
Meet the team on the northern side of the field.
8694
'''
8795
)
8896
)
97+
event_str = event.serialize()
98+
assert 'DURATION:PT30M' in event_str
99+
assert 'DTEND' not in event_str
100+
assert 'DTSTART' in event_str
89101

90-
assert 'DURATION:PT30M' in event
91-
assert 'DTEND' not in event
92-
assert 'DTSTART' in event

yaml2ics.py

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
}
2020

2121

22-
def event_ics_from_yaml(event_yaml: dict) -> str:
22+
def event_from_yaml(event_yaml: dict) -> ics.Event:
2323
d = event_yaml
2424
repeat = d.pop('repeat', None)
2525

@@ -68,32 +68,30 @@ def event_ics_from_yaml(event_yaml: dict) -> str:
6868
rrule_dtstart = rrule_dtstart + 'Z'
6969
rrule_rrule = [line for line in rrule_lines if line.startswith('RRULE')][0]
7070

71-
event_lines = str(event).split('\r\n')
71+
event.extra.append(ics.ContentLine(rrule_rrule))
7272

73-
# Splice in the rrule
74-
out = []
75-
for line in event_lines:
76-
out.append(line)
73+
event.dtstamp = datetime.utcnow().replace(tzinfo=dateutil.tz.UTC)
74+
return event
7775

78-
if line.startswith('DTSTART'):
79-
out.append(rrule_rrule + 'Z')
80-
else:
81-
out = str(event).split('\r\n')
8276

83-
now_utc = datetime.utcnow()
84-
utc_stamp = now_utc.isoformat(
85-
timespec='seconds'
86-
).replace('-', '').replace(':', '') + 'Z'
87-
out.insert(-1, f'DTSTAMP:{utc_stamp}')
88-
89-
return '\r\n'.join(out)
90-
91-
92-
def events_to_calendar_ics(events: dict) -> str:
77+
def events_to_calendar(events: list) -> str:
9378
cal = ics.Calendar()
9479
for event in events:
95-
cal.events.add(event)
96-
return str(cal)
80+
cal.events.append(event)
81+
return cal
82+
83+
def files_to_calendar(files: list) -> ics.Calendar:
84+
"""'main' function: list of files to our result"""
85+
all_events = [ ]
86+
for f in files:
87+
if hasattr(f, 'read'):
88+
calendar_yaml = yaml.load(f.read(), Loader=yaml.FullLoader)
89+
else:
90+
calendar_yaml = yaml.load(open(f, 'r'), Loader=yaml.FullLoader)
91+
for event in calendar_yaml['events']:
92+
all_events.append(event_from_yaml(event))
93+
calendar = events_to_calendar(all_events)
94+
return calendar
9795

9896

9997
if __name__ == '__main__':
@@ -107,10 +105,6 @@ def events_to_calendar_ics(events: dict) -> str:
107105
print(f'Error: {f} is not a file')
108106
sys.exit(-1)
109107

110-
all_events = []
111-
for f in files:
112-
calendar_yaml = yaml.load(open(f, 'r'), Loader=yaml.FullLoader)
113-
for event in calendar_yaml['events']:
114-
all_events.append(event_ics_from_yaml(event))
108+
calendar = files_to_calendar(files)
115109

116-
print(events_to_calendar_ics(all_events))
110+
print(calendar.serialize())

0 commit comments

Comments
 (0)