From 0a9852487cb0e6a1275f1eb1347bf9c836dfdd3a Mon Sep 17 00:00:00 2001 From: Jovial Joe Jayarson Date: Sun, 19 Mar 2023 19:56:32 +0530 Subject: [PATCH] fix: generate dynamic reference docs --- .github/workflows/pages.yml | 2 +- docs/gen_docs.py | 74 +++++++++++++++++++++++++++++++++++++ docs/index.md | 66 ++++++++++++++++----------------- mkdocs.yml | 16 +++++++- 4 files changed, 123 insertions(+), 35 deletions(-) create mode 100644 docs/gen_docs.py diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index fb84a223..7eb89c42 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -37,7 +37,7 @@ jobs: - name: Build documentation run: | source .venv/bin/activate - mkdocs build + python ./docs/gen_docs.py - name: Setup Pages uses: actions/configure-pages@v3 - name: Upload artifact diff --git a/docs/gen_docs.py b/docs/gen_docs.py new file mode 100644 index 00000000..3e1d790a --- /dev/null +++ b/docs/gen_docs.py @@ -0,0 +1,74 @@ +"""Generate docs.""" + +# standard +from shutil import copy, move, rmtree +from yaml import safe_load, safe_dump +from ast import parse, ImportFrom +from typing import Dict, List +from os.path import getsize +from subprocess import run +from pathlib import Path +from sys import argv + + +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" + ) + + +def generate_reference(source: Path, destination: Path): + """Generate reference.""" + nav_items: Dict[str, List[str]] = {"Code Reference": []} + # clean destination + if destination.exists() and destination.is_dir(): + rmtree(destination) + destination.mkdir(exist_ok=True) + # parse source + v_ast = parse(source.read_text(), source) + # generate reference content + for namespace in (node for node in v_ast.body if isinstance(node, ImportFrom)): + if not namespace.module: + continue + for alias in namespace.names: + ref_module = destination / f"{namespace.module}.md" + _write_ref_content(ref_module, namespace.module, alias.name) + nav_items["Code Reference"].append(f"reference/{namespace.module}.md") + return nav_items + + +def update_mkdocs_config(source: Path, destination: Path, nav_items: Dict[str, List[str]]): + """Temporary update to mkdocs config.""" + copy(source, destination) + with open(source, "rt") as mkf: + mkdocs_conf = safe_load(mkf) + mkdocs_conf["nav"] += [nav_items] + with open(source, "wt") as mkf: + safe_dump(mkdocs_conf, mkf, sort_keys=False) + + +def generate_documentation(source: Path): + """Generate documentation.""" + # copy readme as docs index file + copy(source / "README.md", source / "docs/index.md") + # generate reference documentation + nav_items = generate_reference(source / "validators/__init__.py", source / "docs/reference") + # backup mkdocs config + update_mkdocs_config(source / "mkdocs.yml", source / "mkdocs.bak.yml", nav_items) + # build docs as subprocess + print(run(("mkdocs", "build"), capture_output=True).stderr.decode()) + # restore mkdocs config + move(source / "mkdocs.bak.yml", source / "mkdocs.yml") + + +if __name__ == "__main__": + project_dir = Path(__file__).parent.parent + generate_documentation(project_dir) + # use this option before building package + # with `poetry build` to include refs + if len(argv) > 1 and argv[1] == "--keep": + quit() + rmtree(project_dir / "docs/reference") diff --git a/docs/index.md b/docs/index.md index c76eb5a8..d2fc3ab0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,33 +1,33 @@ -# Reference - -::: validators.between - -::: validators.btc_address - -::: validators.card - -::: validators.domain - -::: validators.email - -::: validators.hashes - -::: validators.hostname - -::: validators.iban - -::: validators.ip_address - -::: validators.length - -::: validators.mac_address - -::: validators.slug - -::: validators.url - -::: validators.uuid - ---- - -::: validators.utils +# validators - Python Data Validation for Humans™ + +[![Tests][tests-badge]][tests-link] [![Bandit][bandit-badge]][bandit-link] [![Version Status][vs-badge]][vs-link] [![Downloads][dw-badge]][dw-link] + +Python has all kinds of data validation tools, but every one of them seems to +require defining a schema or form. I wanted to create a simple validation +library where validating a simple value does not require defining a form or a +schema. + +```python +>>> import validators + +>>> validators.email('someone@example.com') +True +``` + +## Resources + +- [Documentation](https://python-validators.github.io/) +- [Issue Tracker](https://github.com/python-validators/validators/issues) +- [Security](https://github.com/python-validators/validators/blob/master/SECURITY.md) +- [Code](https://github.com/python-validators/validators/) + +[//]: #(Links) + +[bandit-badge]: https://github.com/python-validators/validators/actions/workflows/bandit.yml/badge.svg +[bandit-link]: https://github.com/python-validators/validators/actions/workflows/bandit.yml +[tests-badge]: https://github.com/python-validators/validators/actions/workflows/main.yml/badge.svg +[tests-link]: https://github.com/python-validators/validators/actions/workflows/main.yml +[vs-badge]: https://img.shields.io/pypi/v/validators.svg +[vs-link]: https://pypi.python.org/pypi/validators/ +[dw-badge]: https://img.shields.io/pypi/dm/validators.svg +[dw-link]: https://pypi.python.org/pypi/validators/ diff --git a/mkdocs.yml b/mkdocs.yml index 2dfc835a..45f49d12 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,10 +9,24 @@ watch: [README.md, validators/] nav: - Home: index.md - - Code Reference: reference/ theme: name: material + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + primary: white + accent: teal + toggle: + icon: material/toggle-switch + name: Switch to dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: black + accent: teal + toggle: + icon: material/toggle-switch-off-outline + name: Switch to light mode plugins: - search