Skip to content

Commit 8547615

Browse files
committed
Add mkdocs utility to generate API docs pages
This utility is intended to be used as a `mkdocs` `gen_files` plugin script to discover all source files and generate a API documentation page for each. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent 407466c commit 8547615

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

src/frequenz/repo/config/mkdocs.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# License: MIT
2+
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Generate the code reference pages.
5+
6+
It uses the following `mkdocs` plugins:
7+
8+
* `mkdocs-gen-files` to generate the API documentation pages.
9+
* `mkdocs-literate-nav` to make use of the generate `SUMMARY.md` file.
10+
11+
Based on the recipe at:
12+
https://mkdocstrings.github.io/recipes/#automatic-code-reference-pages
13+
"""
14+
15+
from pathlib import Path
16+
from typing import Tuple
17+
18+
import mkdocs_gen_files
19+
20+
21+
def _is_internal(path_parts: Tuple[str, ...]) -> bool:
22+
"""Tell if the path is internal judging by the parts.
23+
24+
Args:
25+
path_parts: Path.parts of the path to check.
26+
27+
Returns:
28+
True if the path is internal.
29+
"""
30+
31+
def with_underscore_not_init(part: str) -> bool:
32+
return part.startswith("_") and part != "__init__"
33+
34+
return any(p for p in path_parts if with_underscore_not_init(p))
35+
36+
37+
def generate_api_pages(src_path: str = "src", dst_path: str = "reference") -> None:
38+
"""Generate API documentation pages for the code.
39+
40+
Internal modules (those starting with an underscore except from `__init__`) are
41+
not included.
42+
43+
A summary page is generated as `SUMMARY.md` which is compatible with the
44+
`mkdocs-literary-nav` plugin.
45+
46+
Args:
47+
src_path: Path where the code is located.
48+
dst_path: Path where the documentation should be generated. This is relative
49+
to the output directory of mkdocs.
50+
"""
51+
# type ignore because mkdocs_gen_files uses a very weird module-level
52+
# __getattr__() which messes up the type system
53+
nav = mkdocs_gen_files.Nav() # type: ignore
54+
55+
for path in sorted(Path(src_path).rglob("*.py")):
56+
module_path = path.relative_to(src_path).with_suffix("")
57+
58+
doc_path = path.relative_to(src_path).with_suffix(".md")
59+
full_doc_path = Path(dst_path, doc_path)
60+
parts = tuple(module_path.parts)
61+
if _is_internal(parts):
62+
continue
63+
if parts[-1] == "__init__":
64+
doc_path = doc_path.with_name("index.md")
65+
full_doc_path = full_doc_path.with_name("index.md")
66+
parts = parts[:-1]
67+
68+
nav[parts] = doc_path.as_posix()
69+
70+
with mkdocs_gen_files.open(full_doc_path, "w") as output_file:
71+
output_file.write(f"::: {'.'.join(parts)}\n")
72+
73+
mkdocs_gen_files.set_edit_path(full_doc_path, Path("..") / path)
74+
75+
with mkdocs_gen_files.open(Path(dst_path) / "SUMMARY.md", "w") as nav_file:
76+
nav_file.writelines(nav.build_literate_nav())

0 commit comments

Comments
 (0)