-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuild_api_ref.py
More file actions
143 lines (123 loc) · 4.94 KB
/
build_api_ref.py
File metadata and controls
143 lines (123 loc) · 4.94 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
from __future__ import annotations
import re
from warnings import warn
from pathlib import Path
from typing import Any
import pkgutil
from pprint import pprint
from importlib import import_module
import inspect
import importlib
MOD = None
MOD_NAME = "sensitivity_jax"
DELIM = "."
def get_summary_line(docs):
try:
line = docs.split("\n\n")[0].replace("\n", " ")
line = re.sub(r"\s+", r" ", line)
return line
except:
return ""
def find_all_modules(root_mod, modules_dir=None, prefix=None):
modules_dir = dict() if modules_dir is None else modules_dir
for _, module_name, ispkg in pkgutil.iter_modules(root_mod.__path__):
module = importlib.import_module(f"{root_mod.__name__}.{module_name}")
function_list = []
for name, obj in inspect.getmembers(module):
if inspect.isfunction(obj) and obj.__doc__ is not None and name[:1] != "_":
if obj.__module__ != module.__name__:
continue
summary = get_summary_line(obj.__doc__)
sig = inspect.signature(obj)
full_name = f"{prefix}{DELIM}{name}" if prefix is not None else name
function_list.append(
dict(name=full_name, summary=summary, signature=sig, doc=obj.__doc__)
)
full_name = f"{prefix}{DELIM}{module_name}" if prefix is not None else module_name
if ispkg:
find_all_modules(module, modules_dir, prefix=full_name)
modules_dir[full_name] = function_list
return modules_dir
def make_table(table_list: list[list[Any]]) -> str:
assert len(table_list)
n_columns = len(table_list[0])
assert all(len(row) == n_columns for row in table_list)
column_lengths = [0 for _ in range(n_columns)]
for row in table_list:
for i, el in enumerate(row):
column_lengths[i] = max(column_lengths[i], len(f" {el} "))
# make table
body = ""
for j, row in enumerate(table_list):
body += (
"|"
+ "|".join([f" {el:^{column_lengths[i] - 2}} " for (i, el) in enumerate(row)])
+ "|\n"
)
if j == 0:
body += "|" + "|".join(["-" * column_len for column_len in column_lengths]) + "|\n"
return body
def make_the_page(
fname: str,
name: str,
signature: inspect.Signature,
doc: str,
path: Path | str,
prev_page: str | None = None,
next_page: str | None = None,
):
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
content = f"""
#
::: {fname}{DELIM}{name.split(DELIM)[-1]}
"""
if prev_page is not None or next_page is not None:
content += "\n<div class='container'>\n"
if prev_page is not None:
content += f"<div class='left-div'><a href='{prev_page[5]}'><<< prev<p>{prev_page[1]}</p></a></div>"
if next_page is not None:
content += f"<div class='right-div'><a href='{next_page[5]}'>next >>><p>{next_page[1]}</p></a></div>"
if prev_page is not None or next_page is not None:
content += "</div>"
path.write_text(content)
def main():
global MOD, MOD_NAME
overview_file = Path("docs/api/overview.md")
if overview_file.exists():
warn(
"Overview file exists, we will not rebuild the documentation. "
+ "Please delete the `docs/api` folder if you want to force a rebuild"
)
return
if MOD is None:
MOD = import_module(MOD_NAME)
overview_page = ""
modules_dir = find_all_modules(MOD, prefix=MOD.__name__)
pages = []
for fname, fn_list in modules_dir.items():
table_rows = [["name", "summary"]]
if len(fn_list) > 0:
for fn in fn_list:
arg_list = ", ".join(list(fn["signature"].parameters.keys()))
name: str = fn["name"]
summary = fn["summary"]
path = f"./docs/api/{fname.replace(DELIM, '/')}/{name.split(DELIM)[-1]}.md"
url = f"/{MOD.__name__}/api" / Path(path).relative_to(Path(*Path(path).parts[:2]))
url = url.with_suffix("")
table_rows.append([f"[{name.split(DELIM)[-1]}({arg_list})]({url})", summary])
pages.append((fname, name, fn["signature"], fn["doc"], path, url))
overview_page += f"\n\n# `{DELIM.join(fname.split(DELIM)[1:])}`\n\n"
overview_page += make_table(table_rows)
overview_file.parent.mkdir(parents=True, exist_ok=True)
overview_file.write_text(overview_page)
for i, (fname, name, signature, doc, path, url) in enumerate(pages):
prev_page = pages[i - 1] if i > 0 else None
next_page = pages[i + 1] if i < len(pages) - 1 else None
make_the_page(fname, name, signature, doc, path, prev_page, next_page)
pprint([page[0] for page in pages])
####################################################################################################
def on_pre_build(*args, **kwargs):
main()
if __name__ == "__main__":
main()