fix: make MkDocs generation filesystem-complete and package-aware

- Add filesystem-based module discovery via `discover_module_paths`
- Decouple documentation coverage from Python import behavior
- Ensure GriffeLoader receives a full module list instead of a single root
- Make MkDocs renderer level-agnostic using global package detection
- Emit `index.md` only for true packages, suppress `<package>.md`
- Mirror full dotted module hierarchy into nested docs directories
- Update CLI, exports, and type stubs to expose discovery helper
- Align tests with filesystem-driven module coverage

This fixes missing docs for submodules and removes invalid package `.md` files.
This commit is contained in:
2026-01-20 23:25:56 +05:30
parent 2e5d330fca
commit dca19caaf3
9 changed files with 120 additions and 41 deletions

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import logging
from pathlib import Path
from typing import List, Optional
from griffe import (
@@ -16,6 +17,41 @@ from docforge.model import Module, Project, DocObject
logger = logging.getLogger(__name__)
def discover_module_paths(
module_name: str,
project_root: Path | None = None,
) -> List[str]:
"""
Discover all Python modules under a package via filesystem traversal.
Rules:
- Directory with __init__.py => package
- .py file => module
- Paths converted to dotted module paths
"""
if project_root is None:
project_root = Path.cwd()
pkg_dir = project_root / module_name
if not pkg_dir.exists():
raise FileNotFoundError(f"Package not found: {pkg_dir}")
module_paths: List[str] = []
for path in pkg_dir.rglob("*.py"):
if path.name == "__init__.py":
module_path = path.parent
else:
module_path = path
rel = module_path.relative_to(project_root)
dotted = ".".join(rel.with_suffix("").parts)
module_paths.append(dotted)
return sorted(set(module_paths))
class GriffeLoader:
"""Loads Python modules using Griffe introspection."""