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,72 @@ 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+ print (run (("sphinx-build" , "docs" , "docs/_build/web" ), capture_output = True ).stderr .decode ())
97+ # build sphinx man pages as subprocess
98+ print (
99+ run (
100+ ("sphinx-build" , "-b" , "man" , "docs" , "docs/_build/man" ), capture_output = True
101+ ).stderr .decode ()
102+ )
103+
104+
105+ def generate_documentation (
106+ source : Path , only_md : bool = False , only_rst : bool = False , discard_refs : bool = True
107+ ):
108+ """Generate documentation."""
109+ if only_md and only_rst :
110+ return
111+ # copy readme as docs index file
112+ copy (source / "README.md" , source / "docs/index.md" )
113+ # clean destination
114+ refs_path = source / "docs/reference"
115+ if refs_path .exists () and refs_path .is_dir ():
116+ rmtree (refs_path )
117+ refs_path .mkdir (exist_ok = True )
118+ # documentation for each kind
119+ if not only_rst :
120+ _gen_md_docs (source , refs_path )
121+ if not only_md :
122+ _gen_rst_docs (source , refs_path )
69123 # optionally discard reference folder
70124 if discard_refs :
71125 rmtree (source / "docs/reference" )
72126
73127
74128if __name__ == "__main__" :
75129 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")
130+ generate_documentation (
131+ project_root ,
132+ only_md = True ,
133+ only_rst = False ,
134+ discard_refs = len (argv ) <= 1 or argv [1 ] != "--keep" ,
135+ )
0 commit comments