-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate.py
180 lines (152 loc) · 5.84 KB
/
generate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import datetime
import argparse
import yaml
import os
from operator import itemgetter
from hashlib import md5
import sys
def get_file_contents(filename):
with open(filename, 'r') as f:
return f.read()
def get_file_list(folder):
'''Return a list of all .yaml files found in a recursive search of
the specified `folder`.'''
file_list = []
for root, subdirs, files in os.walk(folder):
file_list.extend(os.path.join(root, f)
for f in files
if f.lower().endswith("yaml"))
return file_list
def get_details(files):
'''Looks at the YAML data in each file listed in `files`,
and returns two lists: one of details of events in the past,
and one of events in the future.'''
default = {
"time": 900,
"abstract": "",
"disableabstractstart": "",
"disableabstractend": "",
"disablevideostart": "",
"disablevideoend": "",
"videoid": "",
"zoom": "",
"url": "",
"title": "[tbc]",
"speaker": "[tbc]"
}
past = []
future = []
ids = set()
nulldate = datetime.datetime(2018, 1, 1, 0, 0)
for f in files:
detail = {**default, **yaml.safe_load(get_file_contents(f))}
if 'date' not in detail:
print("{} is missing the essential 'date' parameter")
continue
if isinstance(detail['time'], str):
detail['time'] = datetime.datetime.strptime(
detail['time'], "%H:%M"
).time()
else:
detail['time'] = (
nulldate + datetime.timedelta(minutes=detail['time'])
).time()
if not detail['abstract']:
detail['disableabstractstart'] = "<!--"
detail['disableabstractend'] = "-->"
if detail['videoid']:
detail['url'] = f'https://youtu.be/{detail["videoid"]}'
elif detail['zoom'] and detail in future:
detail['url'] = detail['zoom']
else:
detail['disablevideostart'] = "<!--"
detail['disablevideoend'] = "-->"
detail['id'] = md5(repr(detail).encode()).hexdigest()
if detail['id'] not in ids:
ids.add(detail['id'])
if detail["date"] < datetime.date.today():
past.append(detail)
else:
future.append(detail)
return past, future
def group_dates(details):
'''Takes a list of detail dicts (`details`), and returns a
dict of lists of dicts, where each key is a year.'''
details.sort(key=itemgetter('date', 'time'))
if len(details) == 0:
return {}
first_year = details[0]['date'].year
last_year = details[-1]['date'].year
years = {year: [] for year in range(first_year, last_year + 1)}
for detail in details:
years[detail['date'].year].append(detail)
return years
def generate_inner(details, inner_template):
'''Takes a list of `details`, and formats each according
to `inner_template`'''
details.sort(key=itemgetter('date', 'time'))
for detail in details:
yield inner_template.format(**detail)
def year_html(years, inner_template):
'''Takes a dict of lists of events for each year, and
yields tuples of the year and the corresponding HTML,
in reverse chronological order.'''
for year in sorted(years.keys(), reverse=True):
yield year, '\n'.join(reversed(list(
inner_html
for inner_html
in generate_inner(years[year], inner_template)
)))
def generate_html(folder, output_file,
outer_template_file, inner_template_file,
annual_template_file=None):
'''Takes a `folder` of .yaml files and specified `inner_template_file`,
`annual_template_file` and `outer_template_file`,
and generates an HTML page, output at `output_file`.
Syntax for the template files matches Python string formatting,
described in README.md.'''
files = get_file_list(folder)
past_events, future_events = get_details(files)
inner_template = inner_template_file.read()
future_html = '\n'.join(inner_html
for inner_html
in generate_inner(future_events, inner_template))
if annual_template_file:
annual_template = annual_template_file.read()
else:
annual_template = "{content}"
past_html = '\n'.join(
annual_template.format(
year=year,
content=inner_html
)
for year, inner_html
in year_html(group_dates(past_events), inner_template)
)
html = outer_template_file.read().format(
past=past_html, future=future_html
)
output_file.write(html)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description="Takes a folder full of YAML seminar descriptions "
"and arranges them into a HTML page based on the given templates"
)
parser.add_argument("folder",
help="Folder to search recursively for .yaml files")
parser.add_argument("output_file",
help="Where to place the resulting output file",
type=argparse.FileType('w'))
parser.add_argument("--outer_template",
default="outer_template.html",
type=argparse.FileType('r'),
dest="outer_template_file")
parser.add_argument("--inner_template",
default="inner_template.html",
type=argparse.FileType('r'),
dest="inner_template_file")
parser.add_argument("--annual_template",
type=argparse.FileType('r'),
dest="annual_template_file")
args = parser.parse_args()
generate_html(**vars(args))