Skip to content

Commit eb1300b

Browse files
authored
Add 'include' to metadata to include other files. (#11)
Problem statement: I have a directory of files, and want calendars for each (e.g. internal team events, public events). And then I want an "all.ics" that combines all others (or some subset of others). I could modify my Makefile to combile it different ways. But I would rather some way to not mix instructions and definitions. Proposed solution: an `include` field. ``` include: - other.yaml - third.yaml ``` When the file is being loaded, all the events from these other files will be read and inserted into this calendar. This also works recursively. Paths are interpreted relatively
1 parent c150e66 commit eb1300b

2 files changed

Lines changed: 74 additions & 2 deletions

File tree

tests/test_include.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import io
2+
import textwrap
3+
4+
from yaml2ics import files_to_calendar
5+
6+
7+
def _read(f, mode=None):
8+
if f == "a.yaml":
9+
return io.StringIO(
10+
textwrap.dedent(
11+
"""
12+
name: NAME123
13+
include:
14+
- b.yaml
15+
- c.yaml
16+
events:
17+
- summary: AAAAA
18+
begin: 2021-04-22
19+
"""
20+
)
21+
)
22+
if f == "b.yaml":
23+
return io.StringIO(
24+
textwrap.dedent(
25+
"""
26+
include:
27+
- d.yaml
28+
events:
29+
- summary: BBBBB
30+
begin: 2021-04-22
31+
"""
32+
)
33+
)
34+
else:
35+
# Return template with summary of the letters
36+
return io.StringIO(
37+
textwrap.dedent(
38+
"""
39+
events:
40+
- summary: %s
41+
begin: 2021-04-22
42+
"""
43+
% (f[0].upper() * 5)
44+
)
45+
)
46+
47+
48+
def test_include_calendars(monkeypatch):
49+
"""Calendar that includes other calendars"""
50+
monkeypatch.setitem(__builtins__, "open", _read)
51+
cal = files_to_calendar(["a.yaml"])
52+
cal_str = cal.serialize()
53+
assert cal_str.startswith("BEGIN:VCALENDAR")
54+
assert "AAAAA" in cal_str
55+
assert "BBBBB" in cal_str
56+
assert "CCCCC" in cal_str
57+
assert "DDDDD" in cal_str
58+
assert "NAME:NAME123" in cal_str
59+
assert cal_str.endswith("END:VCALENDAR")

yaml2ics.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ def events_to_calendar(events: list) -> str:
9595
return cal
9696

9797

98-
def files_to_calendar(files: list) -> ics.Calendar:
99-
"""'main' function: list of files to our result"""
98+
def files_to_events(files: list) -> (ics.Calendar, str):
99+
"""Process files to a list of events"""
100100
all_events = []
101101
name = None
102102

@@ -108,13 +108,26 @@ def files_to_calendar(files: list) -> ics.Calendar:
108108
tz = calendar_yaml.get("timezone", None)
109109
if tz is not None:
110110
tz = gettz(tz)
111+
if "include" in calendar_yaml:
112+
included_events, _name = files_to_events(
113+
os.path.join(os.path.dirname(f), newfile)
114+
for newfile in calendar_yaml["include"]
115+
)
116+
all_events.extend(included_events)
111117
for event in calendar_yaml.get("events", []):
112118
all_events.append(event_from_yaml(event, tz=tz))
113119

114120
# We can only provide one calendar name, so we'll
115121
# keep the last one we find
116122
name = calendar_yaml.get("name", name)
117123

124+
return all_events, name
125+
126+
127+
def files_to_calendar(files: list) -> ics.Calendar:
128+
"""'main function: list of files to our result"""
129+
all_events, name = files_to_events(files)
130+
118131
calendar = events_to_calendar(all_events)
119132
if name is not None:
120133
calendar.extra.append(ics.ContentLine(name="NAME", value=name))

0 commit comments

Comments
 (0)