feat: docs can be built with both sphinx & mkdocs · python-validators/validators@b2240e7
@@ -8,6 +8,7 @@
88from os.path import getsize
99from subprocess import run
1010from pathlib import Path
11+from sys import argv
11121213# external
1314from yaml import safe_load, safe_dump
@@ -19,28 +20,37 @@ def _write_ref_content(source: Path, module_name: str, func_name: str):
1920"""Write content."""
2021with open(source, "at") as ref:
2122ref.write(
22- (f"# {module_name}\n\n" if getsize(source) == 0 else "")
23-+ f"::: validators.{module_name}.{func_name}\n"
23+ (
24+ (f"# {module_name}\n\n" if getsize(source) == 0 else "")
25++ f"::: validators.{module_name}.{func_name}\n"
26+ )
27+if f"{source}".endswith(".md")
28+else (
29+ (f"{module_name}\n{len(module_name) * '-'}\n\n" if getsize(source) == 0 else "")
30++ f".. module:: validators.{module_name}\n"
31++ f".. autofunction:: {func_name}\n"
32+ )
2433 )
2534263527-def _generate_reference(source: Path, destination: Path):
28-"""Generate reference."""
29-nav_items: Dict[str, List[str]] = {"Code Reference": []}
30-# clean destination
31-if destination.exists() and destination.is_dir():
32-rmtree(destination)
33-destination.mkdir(exist_ok=True)
34-# parse source
36+def _parse_package(source: Path):
37+"""Parse validators package."""
3538v_ast = parse(source.read_text(), source)
36-# generate reference content
3739for namespace in (node for node in v_ast.body if isinstance(node, ImportFrom)):
3840if not namespace.module:
3941continue
40-for alias in namespace.names:
41-ref_module = destination / f"{namespace.module}.md"
42-_write_ref_content(ref_module, namespace.module, alias.name)
43-nav_items["Code Reference"].append(f"reference/{namespace.module}.md")
42+yield (namespace.module, namespace.names)
43+44+45+def _generate_reference(source: Path, destination: Path, ext: str):
46+"""Generate reference."""
47+nav_items: Dict[str, List[str]] = {"Code Reference": []}
48+# generate reference content
49+for module_name, aliases in _parse_package(source):
50+for alias in aliases:
51+_write_ref_content(destination / f"{module_name}.{ext}", module_name, alias.name)
52+if ext == "md":
53+nav_items["Code Reference"].append(f"reference/{module_name}.md")
4454return nav_items
45554656@@ -54,27 +64,71 @@ def _update_mkdocs_config(source: Path, destination: Path, nav_items: Dict[str,
5464safe_dump(mkdocs_conf, mkf, sort_keys=False)
5565566657-def generate_documentation(source: Path, discard_refs: bool = True):
58-"""Generate documentation."""
59-# copy readme as docs index file
60-copy(source / "README.md", source / "docs/index.md")
61-# generate reference documentation
62-nav_items = _generate_reference(source / "validators/__init__.py", source / "docs/reference")
67+def _gen_md_docs(source: Path, refs_path: Path):
68+"""Generate Markdown docs."""
69+nav_items = _generate_reference(source / "validators/__init__.py", refs_path, "md")
6370# backup mkdocs config
64-_update_mkdocs_config(source / "mkdocs.yaml", source / "mkdocs.bak.yml", nav_items)
65-# build docs as subprocess
71+_update_mkdocs_config(source / "mkdocs.yaml", source / "mkdocs.bak.yaml", nav_items)
72+# build mkdocs as subprocess
6673print(run(("mkdocs", "build"), capture_output=True).stderr.decode())
6774# restore mkdocs config
68-move(str(source / "mkdocs.bak.yml"), source / "mkdocs.yaml")
75+move(str(source / "mkdocs.bak.yaml"), source / "mkdocs.yaml")
76+77+78+def _gen_rst_docs(source: Path, refs_path: Path):
79+"""Generate reStructuredText docs."""
80+# external
81+from pypandoc import convert_file # type: ignore
82+83+# generate index.rst
84+with open(source / "docs/index.rst", "wt") as idx_f:
85+idx_f.write(
86+convert_file(source_file=source / "docs/index.md", format="md", to="rst")
87++ "\n\n.. toctree::"
88++ "\n :hidden:"
89++ "\n :maxdepth: 2"
90++ "\n :caption: Reference:"
91++ "\n :glob:\n"
92++ "\n reference/*\n"
93+ )
94+# generate RST reference documentation
95+_generate_reference(source / "validators/__init__.py", refs_path, "rst")
96+# build sphinx web pages as subprocess
97+web_build = run(("sphinx-build", "docs", "docs/_build/web"), capture_output=True)
98+print(web_build.stderr.decode(), "\n", web_build.stdout.decode(), sep="")
99+# build sphinx man pages as subprocess
100+man_build = run(("sphinx-build", "-b", "man", "docs", "docs/_build/man"), capture_output=True)
101+print(man_build.stderr.decode(), "\n", man_build.stdout.decode(), sep="")
102+103+104+def generate_documentation(
105+source: Path, only_md: bool = False, only_rst: bool = False, discard_refs: bool = True
106+):
107+"""Generate documentation."""
108+if only_md and only_rst:
109+return
110+# copy readme as docs index file
111+copy(source / "README.md", source / "docs/index.md")
112+# clean destination
113+refs_path = source / "docs/reference"
114+if refs_path.exists() and refs_path.is_dir():
115+rmtree(refs_path)
116+refs_path.mkdir(exist_ok=True)
117+# documentation for each kind
118+if not only_rst:
119+_gen_md_docs(source, refs_path)
120+if not only_md:
121+_gen_rst_docs(source, refs_path)
69122# optionally discard reference folder
70123if discard_refs:
71124rmtree(source / "docs/reference")
721257312674127if __name__ == "__main__":
75128project_root = Path(__file__).parent.parent
76-generate_documentation(project_root)
77-# NOTE: use following lines only for testing/debugging
78-# generate_documentation(project_root, discard_refs=False)
79-# from sys import argv
80-# generate_documentation(project_root, len(argv) > 1 and argv[1] == "--keep")
129+generate_documentation(
130+project_root,
131+only_md=True,
132+only_rst=False,
133+discard_refs=len(argv) <= 1 or argv[1] != "--keep",
134+ )