88from os .path import getsize
99from subprocess import run
1010from pathlib import Path
11+ from sys import argv
1112
1213# 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."""
2021 with open (source , "at" ) as ref :
2122 ref .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 )
2534
2635
27- 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."""
3538 v_ast = parse (source .read_text (), source )
36- # generate reference content
3739 for namespace in (node for node in v_ast .body if isinstance (node , ImportFrom )):
3840 if not namespace .module :
3941 continue
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" )
4454 return nav_items
4555
4656
@@ -54,27 +64,70 @@ def _update_mkdocs_config(source: Path, destination: Path, nav_items: Dict[str,
5464 safe_dump (mkdocs_conf , mkf , sort_keys = False )
5565
5666
57- 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
6673 print (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+ with open (source / "docs/index.rst" , "wt" ) as idx_f :
84+ idx_f .write (
85+ convert_file (source_file = source / "docs/index.md" , format = "md" , to = "rst" )
86+ + "\n \n .. toctree::"
87+ + "\n :hidden:"
88+ + "\n :maxdepth: 2"
89+ + "\n :caption: Reference:"
90+ + "\n :glob:\n "
91+ + "\n reference/*\n "
92+ )
93+ # generate RST reference documentation
94+ _generate_reference (source / "validators/__init__.py" , refs_path , "rst" )
95+ # build sphinx web pages as subprocess
96+ web_build = run (("sphinx-build" , "docs" , "docs/_build/web" ), capture_output = True )
97+ print (web_build .stderr .decode (), "\n " , web_build .stdout .decode (), sep = "" )
98+ # build sphinx man pages as subprocess
99+ man_build = run (("sphinx-build" , "-b" , "man" , "docs" , "docs/_build/man" ), capture_output = True )
100+ print (man_build .stderr .decode (), "\n " , man_build .stdout .decode (), sep = "" )
101+
102+
103+ def generate_documentation (
104+ source : Path , only_md : bool = False , only_rst : bool = False , discard_refs : bool = True
105+ ):
106+ """Generate documentation."""
107+ if only_md and only_rst :
108+ return
109+ # copy readme as docs index file
110+ copy (source / "README.md" , source / "docs/index.md" )
111+ # clean destination
112+ refs_path = source / "docs/reference"
113+ if refs_path .exists () and refs_path .is_dir ():
114+ rmtree (refs_path )
115+ refs_path .mkdir (exist_ok = True )
116+ # documentation for each kind
117+ if not only_rst :
118+ _gen_md_docs (source , refs_path )
119+ if not only_md :
120+ _gen_rst_docs (source , refs_path )
69121 # optionally discard reference folder
70122 if discard_refs :
71123 rmtree (source / "docs/reference" )
72124
73125
74126if __name__ == "__main__" :
75127 project_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")
128+ generate_documentation (
129+ project_root ,
130+ only_md = True ,
131+ only_rst = False ,
132+ discard_refs = len (argv ) <= 1 or argv [1 ] != "--keep" ,
133+ )
0 commit comments