-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmake.py
144 lines (106 loc) · 4.16 KB
/
make.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
import argparse
import json
import os
languages = ['en', 'fr']
notebook_files = [
'01-dataframe.ipynb',
'02-selection.ipynb',
'03-format.ipynb',
'04-combine.ipynb',
'05-altair.ipynb',
]
def make_nodebook(src_path: str, new_path: str, lang: str, remove_tag: str):
'''Update or rebuild a single notebook from the source notebook
Arguments:
src_path -- relative path to the source notebook file
new_path -- relative path to the new notebook file
lang -- language code, either "en" or "fr"
remove_tag -- if this tag is found, remove the cell from the output
Return value:
The final number of cells in the saved file.
'''
print(f'Building {new_path} ...')
with open(src_path, 'r') as ipynb:
src_dict = json.load(ipynb)
new_cells = []
for cell in src_dict['cells']:
cell_metadata = cell['metadata']
# Skip cells of the other version
if 'tags' in cell_metadata and remove_tag in cell_metadata['tags']:
continue
source_code = cell['source']
# No language required for empty cells
if not source_code:
new_cells.append(cell)
continue
assert 'lang' in cell_metadata, \
f'Cell "{source_code[0]} ..." has no "lang" property'
assert cell_metadata['lang'], \
f'Cell "{source_code[0]} ..." has empty "lang" property'
meta_languages = cell_metadata['lang'].split(',')
for meta_lang in meta_languages:
assert meta_lang in languages, \
f'Cell "{source_code[0]} ..." has invalid lang "{meta_lang}"'
if lang in meta_languages:
new_cells.append(cell)
new_dict = {
'cells': new_cells,
'metadata': src_dict['metadata'],
'nbformat': src_dict['nbformat'],
'nbformat_minor': src_dict['nbformat_minor'],
}
with open(new_path, 'w', newline='\n') as ipynb:
json.dump(new_dict, ipynb, ensure_ascii=False, indent=1)
ipynb.write('\n')
return len(new_cells)
def make_nodebooks(src_file: str, lang: str, force_rebuild: bool = False):
'''Update or rebuild the student and the teacher notebooks of language lang
The student version will have the cells with the tag "exer".
The teacher version will have the cells with the tag "soln".
When there is no specific tag, both versions will have the cell.
Arguments:
src_file -- notebook filename (*.ipynb) expected to be in src/
lang -- language code, either "en" or "fr"
force_rebuild -- if True, it overrides the modification time test
'''
versions = {
'student': {'dir_prefix': '', 'remove_tag': 'soln'},
'teacher': {'dir_prefix': 'solution-', 'remove_tag': 'exer'},
}
nb_cells = {version: 0 for version in versions.keys()}
src_path = os.path.join('src', src_file)
src_mtime = os.path.getmtime(src_path)
for version, attrib in versions.items():
dir_name = f"{attrib['dir_prefix']}{lang}"
new_path = os.path.join(dir_name, src_file)
if os.path.isfile(new_path):
new_mtime = os.path.getmtime(new_path)
else:
new_mtime = 0.0
if (new_mtime < src_mtime) or force_rebuild:
nb_cells[version] = make_nodebook(
src_path,
new_path,
lang,
attrib['remove_tag'])
assert nb_cells['student'] == nb_cells['teacher'], \
f'student and teacher versions have different number of cells ({lang})'
def make_all_nodebooks():
'''Update or rebuild all notebooks
All notebooks:
- for all source files
- for all languages in [en, fr]
- for student and teacher versions
'''
arg_parser = argparse.ArgumentParser(
prog='python make.py',
description='Generates material and solution per language')
arg_parser.add_argument(
'-r', '--rebuild', action='store_true',
help='Force rebuilding notebooks')
args = arg_parser.parse_args()
for src_file in notebook_files:
for lang in languages:
make_nodebooks(src_file, lang, args.rebuild)
if __name__ == '__main__':
make_all_nodebooks()