|
| 1 | +#!/usr/bin/env uv run |
| 2 | +""" |
| 3 | +Script to regenerate the API documentation structure in mkdocs.yml |
| 4 | +based on the current state of the library. |
| 5 | +""" |
| 6 | + |
| 7 | +import logging |
| 8 | +import shutil |
| 9 | +from pathlib import Path |
| 10 | + |
| 11 | +import yaml |
| 12 | + |
| 13 | +# Constants |
| 14 | +ROOT_DIR = Path(__file__).parent.parent |
| 15 | +PACKAGE_NAME = "contraqctor" |
| 16 | +SRC_DIR = ROOT_DIR / "src" / f"{PACKAGE_NAME}" |
| 17 | +DOCS_DIR = ROOT_DIR / "docs" |
| 18 | +API_DIR = DOCS_DIR / "api" |
| 19 | +MKDOCS_YML = ROOT_DIR / "mkdocs.yml" |
| 20 | +API_LABEL = "API Reference" |
| 21 | + |
| 22 | +# Leaving this manual for now. |
| 23 | +DOCUMENTED_MODULES = ["contract", "qc"] |
| 24 | +TO_COPY = ["assets", "examples", "LICENSE"] |
| 25 | +log = logging.getLogger("mkdocs") |
| 26 | + |
| 27 | + |
| 28 | +def on_pre_build(config): |
| 29 | + """Mkdocs pre-build hook.""" |
| 30 | + for file_or_dir in TO_COPY: |
| 31 | + src = ROOT_DIR / file_or_dir |
| 32 | + dest = DOCS_DIR / file_or_dir |
| 33 | + if src.exists(): |
| 34 | + log.info(f"Copying {file_or_dir} to docs...") |
| 35 | + |
| 36 | + if src.is_file(): |
| 37 | + print(f"Copying file {src} to {dest}") |
| 38 | + shutil.copy(src, dest) |
| 39 | + else: |
| 40 | + if dest.exists(): |
| 41 | + shutil.rmtree(dest) |
| 42 | + shutil.copytree(src, dest) |
| 43 | + log.info(f"{file_or_dir} copied successfully.") |
| 44 | + else: |
| 45 | + log.warning(f"Source: {file_or_dir} not found, skipping.") |
| 46 | + |
| 47 | + main() |
| 48 | + |
| 49 | + |
| 50 | +def find_modules(base_dir, module_name): |
| 51 | + """Find all Python modules in the given directory.""" |
| 52 | + modules = [] |
| 53 | + dir_path = base_dir / module_name |
| 54 | + |
| 55 | + if not dir_path.is_dir(): |
| 56 | + return modules |
| 57 | + |
| 58 | + if (dir_path / "__init__.py").exists(): |
| 59 | + modules.append(("core", f"{module_name}")) |
| 60 | + |
| 61 | + for item in dir_path.iterdir(): |
| 62 | + if item.is_file() and item.suffix == ".py" and not item.name.startswith("_"): |
| 63 | + modules.append((item.stem, f"{module_name}.{item.stem}")) |
| 64 | + |
| 65 | + modules.sort(key=lambda x: x[0]) |
| 66 | + |
| 67 | + return modules |
| 68 | + |
| 69 | + |
| 70 | +def generate_api_structure(): |
| 71 | + """Generate the API documentation structure.""" |
| 72 | + api_structure = {} |
| 73 | + |
| 74 | + for module_name in DOCUMENTED_MODULES: |
| 75 | + module_structure = [] |
| 76 | + modules = find_modules(SRC_DIR, module_name) |
| 77 | + |
| 78 | + for name, import_path in modules: |
| 79 | + md_file = f"api/{module_name}/{name}.md" |
| 80 | + |
| 81 | + (API_DIR / module_name).mkdir(parents=True, exist_ok=True) |
| 82 | + |
| 83 | + with open(DOCS_DIR / md_file, "w") as f: |
| 84 | + f.write(f"# {import_path}\n\n") |
| 85 | + f.write(f"::: {PACKAGE_NAME}.{import_path}\n") |
| 86 | + |
| 87 | + module_structure.append({name: md_file}) |
| 88 | + |
| 89 | + api_structure[module_name] = module_structure |
| 90 | + |
| 91 | + return api_structure |
| 92 | + |
| 93 | + |
| 94 | +def update_mkdocs_yml(api_structure): |
| 95 | + """Rewrite the mkdocs.yml overriding the API Reference section only!.""" |
| 96 | + with open(MKDOCS_YML, "r") as f: |
| 97 | + config = yaml.safe_load(f) |
| 98 | + |
| 99 | + nav = config.get("nav") |
| 100 | + for entry in nav: |
| 101 | + if isinstance(entry, dict) and API_LABEL in entry: |
| 102 | + api_ref = ["api/index.md"] |
| 103 | + for module_name, module_content in api_structure.items(): |
| 104 | + api_ref.append({module_name.capitalize(): module_content}) |
| 105 | + entry[API_LABEL] = api_ref |
| 106 | + |
| 107 | + with open(MKDOCS_YML, "w+") as f: |
| 108 | + yaml.dump(config, f, sort_keys=False, default_flow_style=False) |
| 109 | + |
| 110 | + |
| 111 | +def main(): |
| 112 | + """Main function.""" |
| 113 | + log.info("Regenerating API documentation...") |
| 114 | + |
| 115 | + # Generate API structure |
| 116 | + api_structure = generate_api_structure() |
| 117 | + |
| 118 | + # Update mkdocs.yml |
| 119 | + update_mkdocs_yml(api_structure) |
| 120 | + |
| 121 | + log.info("API documentation regenerated successfully.") |
| 122 | + |
| 123 | + |
| 124 | +if __name__ == "__main__": |
| 125 | + main() |
0 commit comments