-
Notifications
You must be signed in to change notification settings - Fork 181
Expand file tree
/
Copy path__main__.py
More file actions
176 lines (153 loc) · 5.96 KB
/
__main__.py
File metadata and controls
176 lines (153 loc) · 5.96 KB
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
"""Generate docs."""
# standard
from ast import ImportFrom, parse
from os import getenv
from os.path import getsize
from pathlib import Path
from shutil import copy
from subprocess import Popen # nosec
def _write_ref_content(source: Path, module_name: str, func_name: str):
"""Write content."""
with open(source, "at") as ref:
ref.write(
(
(f"# {module_name}\n\n" if getsize(source) == 0 else "")
+ f"::: validators.{module_name}.{func_name}\n"
)
if f"{source}".endswith(".md")
else (
(
f"{module_name}\n{len(module_name) * '-'}\n\n"
+ f".. module:: validators.{module_name}\n"
if getsize(source) == 0
else ""
)
+ f".. autofunction:: {func_name}\n"
)
)
def _parse_package(source: Path):
"""Parse validators package."""
v_ast = parse(source.read_text(), source)
for namespace in (node for node in v_ast.body if isinstance(node, ImportFrom)):
if not namespace.module:
continue
yield (namespace.module, namespace.names)
def _gen_md_docs(source: Path, refs_path: Path):
"""Generate Markdown docs."""
# remove existing markdown files
for md_files in (source / "docs/api").glob("*.md"):
md_files.unlink()
# generate md reference documentation
for module_name, aliases in _parse_package(source / "src/validators/__init__.py"):
for alias in aliases:
_write_ref_content(refs_path / f"{module_name}.md", module_name, alias.name)
# build mkdocs as subprocess
mkdocs_build = Popen(("mkdocs", "build")) # nosec
mkdocs_build.communicate()
return mkdocs_build.returncode
def _gen_rst_docs(source: Path, refs_path: Path, only_web: bool = False, only_man: bool = False):
"""Generate reStructuredText docs."""
# external
from pypandoc import convert_file # type: ignore
# remove existing rST files
for rst_files in (source / "docs/api").glob("*.rst"):
rst_files.unlink()
with open(source / "docs/index.rst", "wt") as idx_f:
idx_f.write(
convert_file(source_file=source / "docs/index.md", format="md", to="rst").replace(
"\r\n",
"\n", # remove carriage return in windows
)
+ "\n\n.. toctree::"
+ "\n :hidden:"
+ "\n :maxdepth: 2"
+ "\n :caption: Quick Start:"
+ "\n :glob:\n"
+ "\n install_and_use"
+ "\n\n.. toctree::"
+ "\n :hidden:"
+ "\n :maxdepth: 2"
+ "\n :caption: API Reference:"
+ "\n :glob:\n"
+ "\n api/*\n"
)
with open(source / "docs/install_and_use.rst", "wt") as iau_f:
iau_f.write(
convert_file(source_file=source / "docs/install_and_use.md", format="md", to="rst")
.replace("\r\n", "\n") # remove carriage return in windows
.replace("’", "'")
)
# generate rST reference documentation
for module_name, aliases in _parse_package(source / "src/validators/__init__.py"):
for alias in aliases:
_write_ref_content(refs_path / f"{module_name}.rst", module_name, alias.name)
exit_code = 0
if not only_man:
# build sphinx web pages as subprocess
web_build = Popen(("sphinx-build", "docs", "docs/_build/web"), shell=False) # nosec
web_build.communicate()
exit_code = web_build.returncode
print("Run `python -m http.server -d docs/_build/web` to preview.")
if not only_web:
# build sphinx man pages as subprocess
man_build = Popen( # nosec
("sphinx-build", "-b", "man", "docs", "docs/_build/man"), shell=False
)
man_build.communicate()
copy(source / "docs/_build/man/validators.1", source / "docs/validators.1")
print(f"Man page copied to: {source / 'docs/validators.1'}")
exit_code = man_build.returncode if exit_code == 0 else exit_code
return exit_code
def _generate_documentation(
source: Path,
only_md: bool = False,
only_rst_web: bool = False,
only_rst_man: bool = False,
):
"""Generate documentation."""
if only_md is only_rst_web is only_rst_man is True:
return
if only_md is only_rst_web is only_rst_man is False:
return
# copy readme as docs index file
copy(source / "README.md", source / "docs/index.md")
# clean destination
refs_path = source / "docs/api"
# if refs_path.is_dir():
# rmtree(refs_path)
refs_path.mkdir(exist_ok=True)
exit_code = 0 if (only_rst_web or only_rst_man) else _gen_md_docs(source, refs_path)
if not only_md:
exit_code = (
_gen_rst_docs(source, refs_path, only_rst_web, only_rst_man)
if exit_code == 0
else exit_code
)
return exit_code
def package(source: Path):
"""Package the source code."""
_generate_documentation(source, only_rst_man=True)
if getenv("CI", "false") == "true":
process = Popen(("./.venv/bin/python", "-m", "build"), shell=False) # nosec
else:
process = Popen(("pdm", "build"), shell=False) # nosec
process.communicate()
return process.returncode
if __name__ == "__main__":
project_root = Path(__file__).parent.parent.parent
exit_code = 0
# standard
from sys import argv
if len(argv) != 2:
print("Expected one of these augments: `pkg` `doc` `man` or `web`")
quit(1)
if argv[1] == "pkg":
exit_code = package(project_root)
elif argv[1] == "doc":
exit_code = _generate_documentation(project_root, only_md=True)
elif argv[1] == "man":
exit_code = _generate_documentation(project_root, only_rst_man=True)
elif argv[1] == "web":
exit_code = _generate_documentation(project_root, only_rst_web=True)
quit(exit_code)
# TODO: Address all '# nosec'