-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathyaml_to_html.py
More file actions
executable file
·143 lines (110 loc) · 4.45 KB
/
yaml_to_html.py
File metadata and controls
executable file
·143 lines (110 loc) · 4.45 KB
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
#!/usr/bin/env python3
import pandas as pd
import yaml
import shutil
from html import escape
import re
URL_RE = re.compile(r'\b((?:https?://|www\.)[^\s<>"\']+)', re.IGNORECASE)
def linkify_cell(value):
if not isinstance(value, str):
return value
def repl(m):
url = m.group(1)
href = url if url.lower().startswith(("http://", "https://")) else f"https://{url}"
return f'<a href="{href}">{url}</a>'
return URL_RE.sub(repl, value)
def to_problem_id(value):
if not isinstance(value, str):
return ""
normalized = value.strip().lower().replace("-", "_").replace(" ", "_")
normalized = re.sub(r"[^a-z0-9_]", "", normalized)
normalized = re.sub(r"_+", "_", normalized).strip("_")
return normalized
def add_problem_id_row_attributes(table_html, problem_ids):
marker = "<tbody>"
if marker not in table_html:
return table_html
body_start = table_html.index(marker) + len(marker)
prefix = table_html[:body_start]
body = table_html[body_start:]
for problem_id in problem_ids:
safe_id = escape(problem_id, quote=True)
body = body.replace("<tr>", f'<tr data-problem-id="{safe_id}">', 1)
return prefix + body
yaml_file = "problems.yaml"
html_dir = "docs/"
html_table = f"{html_dir}problems.html"
html_header = f"{html_dir}header.html"
html_scripts = f"{html_dir}javascript.html"
html_footer = f"{html_dir}footer.html"
html_index = f"{html_dir}index.html"
html_table_template = f"{html_dir}table_template.html"
default_columns = ["name",
"textual description",
"suite/generator/single",
"objectives",
"dimensionality",
"variable type",
"constraints",
"dynamic",
"noise",
"multi-fidelity",
"source (real-world/artificial)",
"reference",
"implementation"]
if __name__ == "__main__":
# Load data
with open(yaml_file) as yaml_input:
raw_data = pd.json_normalize(yaml.safe_load(yaml_input))
if "problem_id" in raw_data.columns:
problem_ids = raw_data["problem_id"].fillna("").map(str)
else:
problem_ids = raw_data["name"].fillna("").map(str).map(to_problem_id)
problem_ids = problem_ids.where(problem_ids.str.len() > 0, raw_data["name"].fillna("").map(str).map(to_problem_id))
data = raw_data.copy()
# Choose desired columns
all_columns = False
if all_columns is False:
columns = default_columns
data = data[columns]
data = data.map(linkify_cell)
# Generate plain table
table = data.to_html(render_links=False,
escape=False, # Don't escape HTML in cells (to allow links)
index=False,
table_id="problems",
classes=["display compact", "display", "styled-table"], # Set display style
border=0,
na_rep="") # Leave NaN cells empty
table = add_problem_id_row_attributes(table, problem_ids.tolist())
# Add footer to facilitate individual column search
idx = table.index('</table>')
final_table = table[:idx] + "<tfoot><tr>" + " ".join(["<th>"+ i +"</th>" for i in data.columns])+"</tr> </tfoot>" + table[idx:]
default_hidden_columns = {"textual description", "reference", "implementation"}
column_toggles = "".join(
[
(
f'<label class="column-chip">'
f'<input class="col-toggle" type="checkbox" data-column="{i}"'
f'{" checked" if col not in default_hidden_columns else ""}>'
f'<span>{escape(col)}</span>'
f'</label>'
)
for i, col in enumerate(data.columns)
]
)
with open(html_table_template, encoding="utf-8") as template_file:
table_template = template_file.read()
table_markup = (
table_template
.replace("__COLUMN_TOGGLES__", column_toggles)
.replace("__TABLE__", final_table)
)
# Write table to file
with open(html_table, "w", encoding="utf-8") as table_file:
table_file.write(table_markup)
# Merge table and scripts into HTML page
with open(html_index, "wb") as output_file:
for part_path in [html_header, html_table, html_scripts, html_footer]:
with open(part_path, "rb") as part_file:
shutil.copyfileobj(part_file, output_file)