diff --git a/docs/openapi_first/app.md b/docs/openapi_first/app.md new file mode 100644 index 0000000..f289c43 --- /dev/null +++ b/docs/openapi_first/app.md @@ -0,0 +1,3 @@ +# App + +::: openapi_first.app diff --git a/docs/openapi_first/binder.md b/docs/openapi_first/binder.md new file mode 100644 index 0000000..045baf3 --- /dev/null +++ b/docs/openapi_first/binder.md @@ -0,0 +1,3 @@ +# Binder + +::: openapi_first.binder diff --git a/docs/openapi_first/errors.md b/docs/openapi_first/errors.md new file mode 100644 index 0000000..fe3b381 --- /dev/null +++ b/docs/openapi_first/errors.md @@ -0,0 +1,3 @@ +# Errors + +::: openapi_first.errors diff --git a/docs/openapi_first/index.md b/docs/openapi_first/index.md new file mode 100644 index 0000000..02dd173 --- /dev/null +++ b/docs/openapi_first/index.md @@ -0,0 +1,3 @@ +# Openapi First + +::: openapi_first diff --git a/docs/openapi_first/loader.md b/docs/openapi_first/loader.md new file mode 100644 index 0000000..f557311 --- /dev/null +++ b/docs/openapi_first/loader.md @@ -0,0 +1,3 @@ +# Loader + +::: openapi_first.loader diff --git a/manage_docs.py b/manage_docs.py new file mode 100644 index 0000000..c6f99aa --- /dev/null +++ b/manage_docs.py @@ -0,0 +1,159 @@ +""" +MkDocs documentation management CLI. + +This script provides a proper CLI interface to: +- Generate MkDocs Markdown files with mkdocstrings directives +- Build the documentation site +- Serve the documentation site locally + +All operations are performed by calling MkDocs as a Python library +(no shell command invocation). + +Requirements: +- mkdocs +- mkdocs-material +- mkdocstrings[python] + +Usage: + python manage_docs.py generate + python manage_docs.py build + python manage_docs.py serve + +Optional flags: + --docs-dir PATH Path to docs directory (default: ./docs) + --package-root NAME Root Python package name (default: mail_intake) +""" + +from __future__ import annotations + +import argparse +from pathlib import Path + +from mkdocs.commands import build as mkdocs_build +from mkdocs.commands import serve as mkdocs_serve +from mkdocs.config import load_config + + +PROJECT_ROOT = Path(__file__).resolve().parent +DEFAULT_DOCS_DIR = PROJECT_ROOT / "docs" +DEFAULT_PACKAGE_ROOT = "openapi_first" +MKDOCS_YML = PROJECT_ROOT / "mkdocs.yml" + + +def generate_docs_from_nav( + project_root: Path, + docs_root: Path, + package_root: str, +) -> None: + """ + Create and populate MkDocs Markdown files with mkdocstrings directives. + + This function: + - Walks the Python package structure + - Mirrors it under the docs directory + - Creates missing .md files + - Creates index.md for packages (__init__.py) + - Overwrites content with ::: package.module + + Examples: + mail_intake/__init__.py -> docs/mail_intake/index.md + mail_intake/config.py -> docs/mail_intake/config.md + mail_intake/adapters/__init__.py -> docs/mail_intake/adapters/index.md + mail_intake/adapters/base.py -> docs/mail_intake/adapters/base.md + """ + + package_dir = project_root / package_root + if not package_dir.exists(): + raise FileNotFoundError(f"Package not found: {package_dir}") + + docs_root.mkdir(parents=True, exist_ok=True) + + for py_file in package_dir.rglob("*.py"): + rel = py_file.relative_to(project_root) + + if py_file.name == "__init__.py": + # Package → index.md + module_path = ".".join(rel.parent.parts) + md_path = docs_root / rel.parent / "index.md" + title = rel.parent.name.replace("_", " ").title() + else: + # Regular module → .md + module_path = ".".join(rel.with_suffix("").parts) + md_path = docs_root / rel.with_suffix(".md") + title = md_path.stem.replace("_", " ").title() + + md_path.parent.mkdir(parents=True, exist_ok=True) + + content = f"""# {title} + +::: {module_path} +""" + + md_path.write_text(content, encoding="utf-8") + + +def load_mkdocs_config(): + if not MKDOCS_YML.exists(): + raise FileNotFoundError("mkdocs.yml not found at project root") + return load_config(str(MKDOCS_YML)) + + +def cmd_generate(args: argparse.Namespace) -> None: + generate_docs_from_nav( + project_root=PROJECT_ROOT, + docs_root=args.docs_dir, + package_root=args.package_root, + ) + + +def cmd_build(_: argparse.Namespace) -> None: + config = load_mkdocs_config() + mkdocs_build.build(config) + + +def cmd_serve(_: argparse.Namespace) -> None: + mkdocs_serve.serve( + config_file=str(MKDOCS_YML) + ) + +def main() -> None: + parser = argparse.ArgumentParser( + prog="manage_docs.py", + description="Manage MkDocs documentation for the project", + ) + + parser.add_argument( + "--docs-dir", + type=Path, + default=DEFAULT_DOCS_DIR, + help="Path to the docs directory", + ) + parser.add_argument( + "--package-root", + default=DEFAULT_PACKAGE_ROOT, + help="Root Python package name", + ) + + subparsers = parser.add_subparsers(dest="command", required=True) + + subparsers.add_parser( + "generate", + help="Generate Markdown files with mkdocstrings directives", + ).set_defaults(func=cmd_generate) + + subparsers.add_parser( + "build", + help="Build the MkDocs site", + ).set_defaults(func=cmd_build) + + subparsers.add_parser( + "serve", + help="Serve the MkDocs site locally", + ).set_defaults(func=cmd_serve) + + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..53bd282 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,47 @@ +site_name: Aetoskia Mail Intake +site_description: Format-agnostic document reading, parsing, and scraping framework + +theme: + name: material + palette: + - scheme: slate + primary: deep purple + accent: cyan + font: + text: Inter + code: JetBrains Mono + features: + - navigation.tabs + - navigation.expand + - navigation.top + - navigation.instant + - content.code.copy + - content.code.annotate + +plugins: + - search + - mkdocstrings: + handlers: + python: + paths: ["."] + options: + docstring_style: google + show_source: false + show_signature_annotations: true + separate_signature: true + merge_init_into_class: true + inherited_members: true + annotations_path: brief + show_root_heading: true + group_by_category: true + +nav: + - Home: openapi_first/index.md + + - Core: + - OpenAPI-First App: openapi_first/app.md + - Route Binder: openapi_first/binder.md + - Spec Loaders: openapi_first/loaders.md + + - Errors: + - Error Hierarchy: openapi_first/errors.md