-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathapi_pages.py
149 lines (114 loc) · 5.24 KB
/
api_pages.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
# License: MIT
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH
"""Generate the code reference pages.
It uses the following `mkdocs` plugins:
* `mkdocs-gen-files` to generate the API documentation pages.
* `mkdocs-literate-nav` to make use of the generate `SUMMARY.md` file.
Based on the recipe at:
https://mkdocstrings.github.io/recipes/#automatic-code-reference-pages
"""
import subprocess
import tempfile
from pathlib import Path
from typing import Tuple
import mkdocs_gen_files
from .. import protobuf as _protobuf
def _is_internal(path_parts: Tuple[str, ...]) -> bool:
"""Tell if the path is internal judging by the parts.
Args:
path_parts: Path.parts of the path to check.
Returns:
True if the path is internal.
"""
def with_underscore_not_init(part: str) -> bool:
return part.startswith("_") and part != "__init__"
is_conftest = path_parts[-1] == "conftest" if path_parts else False
return is_conftest or any(p for p in path_parts if with_underscore_not_init(p))
def generate_python_api_pages(
src_path: str = "src", dst_path: str = "python-reference"
) -> None:
"""Generate API documentation pages for the code.
Internal modules (those starting with an underscore except from `__init__`) are
not included.
A summary page is generated as `SUMMARY.md` which is compatible with the
`mkdocs-literary-nav` plugin.
Args:
src_path: Path where the code is located.
dst_path: Path where the documentation should be generated. This is relative
to the output directory of mkdocs.
"""
# type ignore because mkdocs_gen_files uses a very weird module-level
# __getattr__() which messes up the type system
nav = mkdocs_gen_files.Nav() # type: ignore
for path in sorted(Path(src_path).rglob("*.py")):
module_path = path.relative_to(src_path).with_suffix("")
doc_path = path.relative_to(src_path).with_suffix(".md")
full_doc_path = Path(dst_path, doc_path)
parts = tuple(module_path.parts)
if _is_internal(parts):
continue
if parts[-1] == "__init__":
doc_path = doc_path.with_name("index.md")
full_doc_path = full_doc_path.with_name("index.md")
parts = parts[:-1]
nav[parts] = doc_path.as_posix()
with mkdocs_gen_files.open(full_doc_path, "w") as output_file:
output_file.write(f"::: {'.'.join(parts)}\n")
mkdocs_gen_files.set_edit_path(full_doc_path, Path("..") / path)
with mkdocs_gen_files.open(Path(dst_path) / "SUMMARY.md", "w") as nav_file:
nav_file.writelines(nav.build_literate_nav())
def generate_protobuf_api_pages(
src_path: str = "proto", dst_path: str = "protobuf-reference"
) -> None:
"""Generate API documentation pages for the code.
Internal modules (those starting with an underscore except from `__init__`) are
not included.
A summary page is generated as `SUMMARY.md` which is compatible with the
`mkdocs-literary-nav` plugin.
Args:
src_path: Path where the code is located.
dst_path: Path where the documentation should be generated. This is relative
to the output directory of mkdocs.
"""
# type ignore because mkdocs_gen_files uses a very weird module-level
# __getattr__() which messes up the type system
nav = mkdocs_gen_files.Nav() # type: ignore
config = _protobuf.ProtobufConfig.from_pyproject_toml(
proto_path=src_path, docs_path=dst_path
)
cwd = Path.cwd()
with tempfile.TemporaryDirectory(prefix="mkdocs-protobuf-reference-") as tmp_path:
for path in sorted(Path(config.proto_path).rglob("*.proto")):
doc_path = path.relative_to(config.proto_path).with_suffix(".md")
full_doc_path = Path(config.docs_path, doc_path)
parts = tuple(path.relative_to(config.proto_path).parts)
nav[parts] = doc_path.as_posix()
doc_tmp_path = tmp_path / doc_path
doc_tmp_path.parent.mkdir(parents=True, exist_ok=True)
try:
subprocess.run(
[
"docker",
"run",
"--rm",
f"-v{cwd}:{cwd}",
f"-v{tmp_path}:{tmp_path}",
"pseudomuto/protoc-gen-doc",
f"-I{cwd / config.proto_path}",
*(f"-I{cwd / p}" for p in config.include_paths),
f"--doc_opt=markdown,{doc_path.name}",
f"--doc_out={tmp_path / doc_path.parent}",
str(cwd / path),
],
check=True,
)
except subprocess.CalledProcessError as error:
print(f"Error generating protobuf reference page: {error}")
with (
doc_tmp_path.open() as input_file,
mkdocs_gen_files.open(full_doc_path, "w") as output_file,
):
output_file.write(input_file.read())
mkdocs_gen_files.set_edit_path(full_doc_path, Path("..") / path)
with mkdocs_gen_files.open(Path(config.docs_path) / "SUMMARY.md", "w") as nav_file:
nav_file.writelines(nav.build_literate_nav())