Compare commits

4 Commits

Author SHA1 Message Date
678f522456 (0.0.3): Refactor - Modular CLI Structure, Type Synchronization, and Documentation Audit
All checks were successful
continuous-integration/drone/tag Build is passing
2026-01-21 18:59:09 +05:30
ff92906720 cli-cleanup (#2)
Some checks reported errors
continuous-integration/drone/tag Build was killed
Reviewed-on: #2
Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
2026-01-21 13:25:57 +00:00
94c1818103 cli-cleanup (#1)
Reviewed-on: #1
Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
2026-01-21 13:23:32 +00:00
15c59ab274 doc changes 2026-01-21 17:36:08 +05:30
51 changed files with 2434 additions and 1558 deletions

View File

@@ -21,4 +21,6 @@ groups:
CLI: CLI:
- docforge/cli/index.md - docforge/cli/index.md
- docforge/cli/main.md - docforge/cli/main.md
- docforge/cli/mkdocs.md - docforge/cli/commands.md
- docforge/cli/mcp_utils.md
- docforge/cli/mkdocs_utils.md

View File

@@ -6,6 +6,12 @@ speed, flexibility, and beautiful output. It decouples the introspection of
your code from the rendering process, allowing you to generate documentation your code from the rendering process, allowing you to generate documentation
for various platforms (starting with MkDocs) from a single internal models. for various platforms (starting with MkDocs) from a single internal models.
## Available Commands
- **build**: Build documentation (MkDocs site or MCP resources).
- **serve**: Serve documentation (MkDocs or MCP).
- **tree**: Visualize the introspected project structure.
## Installation ## Installation
Install using `pip` with the optional `mkdocs` dependencies for a complete setup: Install using `pip` with the optional `mkdocs` dependencies for a complete setup:
@@ -16,10 +22,14 @@ pip install doc-forge
## Quick Start ## Quick Start
1. **Generate Markdown Sources**: 1. **Build Documentation**:
Introspect your package and create ready-to-use Markdown files: Introspect your package and generate documentation in one step:
```bash ```bash
doc-forge generate --module my_package --docs-dir docs # Build MkDocs site
doc-forge build --mkdocs --module my_package --site-name "My Docs"
# Build MCP resources
doc-forge build --mcp --module my_package
``` ```
2. **Define Navigation**: 2. **Define Navigation**:
@@ -33,14 +43,13 @@ pip install doc-forge
- my_package/utils.md - my_package/utils.md
``` ```
3. **Generate MkDocs Configuration**: 3. **Preview**:
```bash ```bash
doc-forge mkdocs --site-name "My Awesome Docs" # Serve MkDocs site
``` doc-forge serve --mkdocs
4. **Preview**: # Serve MCP documentation
```bash doc-forge serve --mcp
doc-forge serve
``` ```
## Project Structure ## Project Structure

View File

@@ -6,11 +6,9 @@ with doc-forge.
## Available Commands ## Available Commands
- **build**: Build documentation (MkDocs site or MCP resources).
- **serve**: Serve documentation (MkDocs or MCP).
- **tree**: Visualize the introspected project structure. - **tree**: Visualize the introspected project structure.
- **generate**: Create Markdown source files from Python code.
- **mkdocs**: Generate the primary `mkdocs.yml` configuration.
- **build**: Build the final documentation site.
- **serve**: Launch a local development server with live-reloading.
""" """
from .main import main from .main import main

166
docforge/cli/commands.py Normal file
View File

@@ -0,0 +1,166 @@
import click
from pathlib import Path
from typing import Sequence, Optional
from docforge.loaders import GriffeLoader
from docforge.cli import mkdocs_utils
from docforge.cli import mcp_utils
@click.group()
def cli() -> None:
"""
doc-forge CLI: A tool for introspecting Python projects and generating
documentation.
"""
pass
@cli.command()
@click.option("--mcp", is_flag=True, help="Build MCP resources")
@click.option("--mkdocs", is_flag=True, help="Build MkDocs site")
@click.option("--module", help="Python module to document")
@click.option("--project-name", help="Project name override")
# MkDocs specific
@click.option("--site-name", help="MkDocs site name")
@click.option("--docs-dir", type=click.Path(path_type=Path), default=Path("docs"), help="Directory for MD sources")
@click.option("--nav", "nav_file", type=click.Path(path_type=Path), default=Path("docforge.nav.yml"),
help="Nav spec path")
@click.option("--template", type=click.Path(path_type=Path), help="MkDocs template path")
@click.option("--mkdocs-yml", type=click.Path(path_type=Path), default=Path("mkdocs.yml"), help="Output config path")
# MCP specific
@click.option("--out-dir", type=click.Path(path_type=Path), default=Path("mcp_docs"), help="MCP output directory")
def build(
mcp: bool,
mkdocs: bool,
module: Optional[str],
project_name: Optional[str],
site_name: Optional[str],
docs_dir: Path,
nav_file: Path,
template: Optional[Path],
mkdocs_yml: Path,
out_dir: Path,
) -> None:
"""
Build documentation (MkDocs site or MCP resources).
This command orchestrates the full build process:
1. Introspects the code (Griffe)
2. Renders sources (MkDocs Markdown or MCP JSON)
3. (MkDocs only) Generates config and runs the final site build.
Args:
mcp: Use the MCP documentation builder.
mkdocs: Use the MkDocs documentation builder.
module: The dotted path of the module to document.
project_name: Optional override for the project name.
site_name: (MkDocs) The site display name. Defaults to module name.
docs_dir: (MkDocs) Target directory for Markdown sources.
nav_file: (MkDocs) Path to the docforge.nav.yml specification.
template: (MkDocs) Optional custom mkdocs.yml template.
mkdocs_yml: (MkDocs) Target path for the generated mkdocs.yml.
out_dir: (MCP) Target directory for MCP JSON resources.
"""
if not mcp and not mkdocs:
raise click.UsageError("Must specify either --mcp or --mkdocs")
if mkdocs:
if not module:
raise click.UsageError("--module is required for MkDocs build")
if not site_name:
site_name = module
click.echo(f"Generating MkDocs sources in {docs_dir}...")
mkdocs_utils.generate_sources(module, project_name, docs_dir)
click.echo(f"Generating MkDocs config {mkdocs_yml}...")
mkdocs_utils.generate_config(docs_dir, nav_file, template, mkdocs_yml, site_name)
click.echo("Running MkDocs build...")
mkdocs_utils.build(mkdocs_yml)
click.echo("MkDocs build completed.")
if mcp:
if not module:
raise click.UsageError("--module is required for MCP build")
click.echo(f"Generating MCP resources in {out_dir}...")
mcp_utils.generate_resources(module, project_name, out_dir)
click.echo("MCP build completed.")
@cli.command()
@click.option("--mcp", is_flag=True, help="Serve MCP documentation")
@click.option("--mkdocs", is_flag=True, help="Serve MkDocs site")
@click.option("--mkdocs-yml", type=click.Path(path_type=Path), default=Path("mkdocs.yml"), help="MkDocs config path")
@click.option("--out-dir", type=click.Path(path_type=Path), default=Path("mcp_docs"), help="MCP root directory")
def serve(
mcp: bool,
mkdocs: bool,
mkdocs_yml: Path,
out_dir: Path,
) -> None:
"""
Serve documentation (MkDocs or MCP).
Args:
mcp: Serve MCP resources via an MCP server.
mkdocs: Serve the MkDocs site using the built-in development server.
mkdocs_yml: (MkDocs) Path to the mkdocs.yml configuration.
out_dir: (MCP) Path to the mcp_docs/ directory.
"""
if mcp and mkdocs:
raise click.UsageError("Cannot specify both --mcp and --mkdocs")
if not mcp and not mkdocs:
raise click.UsageError("Must specify either --mcp or --mkdocs")
if mkdocs:
mkdocs_utils.serve(mkdocs_yml)
elif mcp:
mcp_utils.serve(out_dir)
@cli.command()
@click.option(
"--modules",
multiple=True,
required=True,
help="Python module import paths to introspect",
)
@click.option(
"--project-name",
help="Project name (defaults to first module)",
)
def tree(
modules: Sequence[str],
project_name: Optional[str],
) -> None:
"""
Visualize the project structure in the terminal.
Args:
modules: List of module import paths to recursively introspect.
project_name: Optional override for the project name shown at the root.
"""
loader = GriffeLoader()
project = loader.load_project(list(modules), project_name)
click.echo(project.name)
for module in project.get_all_modules():
click.echo(f"├── {module.path}")
for obj in module.get_all_objects():
_print_object(obj, indent="")
def _print_object(obj, indent: str) -> None:
"""
Recursive helper to print doc objects and their members to the console.
Args:
obj: The DocObject instance to print.
indent: Current line indentation (e.g., '').
"""
click.echo(f"{indent}├── {obj.name}")
for member in obj.get_all_members():
_print_object(member, indent + "")

32
docforge/cli/commands.pyi Normal file
View File

@@ -0,0 +1,32 @@
from click.core import Group
from pathlib import Path
from typing import Sequence, Optional, Any
cli: Group
def build(
mcp: bool,
mkdocs: bool,
module: Optional[str],
project_name: Optional[str],
site_name: Optional[str],
docs_dir: Path,
nav_file: Path,
template: Optional[Path],
mkdocs_yml: Path,
out_dir: Path,
) -> None: ...
def serve(
mcp: bool,
mkdocs: bool,
mkdocs_yml: Path,
out_dir: Path,
) -> None: ...
def tree(
modules: Sequence[str],
project_name: Optional[str],
) -> None: ...
def _print_object(obj: Any, indent: str) -> None: ...

View File

@@ -1,271 +1,14 @@
""" """
Main entry point for the doc-forge CLI. This module defines the core command Main entry point for the doc-forge CLI. This module delegates all command
group and the 'tree', 'generate', 'build', and 'serve' commands. execution to docforge.cli.commands.
""" """
from docforge.cli.commands import cli
from pathlib import Path
from typing import Sequence, Optional
import click
from docforge.loaders import GriffeLoader, discover_module_paths
from docforge.renderers import MkDocsRenderer, MCPRenderer
from docforge.cli.mkdocs import mkdocs_cmd
@click.group()
def cli() -> None:
"""
doc-forge CLI: A tool for introspecting Python projects and generating
documentation.
"""
pass
cli.add_command(mkdocs_cmd)
# ---------------------------------------------------------------------
# tree
# ---------------------------------------------------------------------
@cli.command()
@click.option(
"--modules",
multiple=True,
required=True,
help="Python module import paths to introspect",
)
@click.option(
"--project-name",
help="Project name (defaults to first module)",
)
def tree(
modules: Sequence[str],
project_name: Optional[str],
) -> None:
"""
Visualize the project structure including modules and their members.
Args:
modules: List of module paths to introspect.
project_name: Optional project name override.
"""
loader = GriffeLoader()
project = loader.load_project(list(modules), project_name)
click.echo(project.name)
for module in project.get_all_modules():
click.echo(f"├── {module.path}")
for obj in module.get_all_objects():
_print_object(obj, indent="")
def _print_object(obj, indent: str) -> None:
"""
Recursive helper to print doc objects.
"""
click.echo(f"{indent}├── {obj.name}")
for member in obj.get_all_members():
_print_object(member, indent + "")
# ---------------------------------------------------------------------
# generate
# ---------------------------------------------------------------------
@cli.command()
@click.option(
"--module",
required=True,
help="Python module import paths to document",
)
@click.option(
"--project-name",
help="Project name (defaults to first module)",
)
@click.option(
"--docs-dir",
type=click.Path(path_type=Path),
default=Path("docs"),
)
def generate(
module: str,
project_name: Optional[str],
docs_dir: Path,
) -> None:
"""
Generate Markdown source files for the specified module.
Args:
module: The primary module path to document.
project_name: Optional project name override.
docs_dir: Directory where documentation sources will be written.
"""
loader = GriffeLoader()
discovered_paths = discover_module_paths(
module,
)
project = loader.load_project(
discovered_paths,
project_name
)
renderer = MkDocsRenderer()
renderer.generate_sources(project, docs_dir)
click.echo(f"Documentation sources generated in {docs_dir}")
# ---------------------------------------------------------------------
# mcp-build
# ---------------------------------------------------------------------
@cli.command(name="generate-mcp")
@click.option(
"--module",
required=True,
help="Python module import path to document",
)
@click.option(
"--project-name",
help="Project name (defaults to first module)",
)
@click.option(
"--out-dir",
type=click.Path(path_type=Path),
default=Path("mcp_docs"),
)
def generate_mcp(
module: str,
project_name: str | None,
out_dir: Path,
) -> None:
"""
Generate MCP-compatible documentation resources for the specified module.
Args:
module: The primary module path to document.
project_name: Optional project name override.
out_dir: Directory where MCP resources will be written.
"""
loader = GriffeLoader()
discovered_paths = discover_module_paths(module)
project = loader.load_project(
discovered_paths,
project_name,
)
renderer = MCPRenderer()
renderer.generate_sources(project, out_dir)
click.echo(f"MCP documentation resources generated in {out_dir}")
# ---------------------------------------------------------------------
# build
# ---------------------------------------------------------------------
@cli.command()
@click.option(
"--mkdocs-yml",
type=click.Path(path_type=Path),
default=Path("mkdocs.yml"),
)
def build(mkdocs_yml: Path) -> None:
"""
Build the documentation site using MkDocs.
Args:
mkdocs_yml: Path to the mkdocs.yml configuration file.
"""
if not mkdocs_yml.exists():
raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}")
from mkdocs.config import load_config
from mkdocs.commands.build import build as mkdocs_build
mkdocs_build(load_config(str(mkdocs_yml)))
click.echo("MkDocs build completed")
# ---------------------------------------------------------------------
# serve-mcp
# ---------------------------------------------------------------------
@cli.command(name="serve-mcp")
def serve_mcp() -> None:
"""
Serve MCP documentation from the local mcp_docs directory.
"""
from docforge.servers import MCPServer
mcp_root = Path.cwd() / "mcp_docs"
if not mcp_root.exists():
raise click.ClickException("mcp_docs directory not found")
required = [
mcp_root / "index.json",
mcp_root / "nav.json",
mcp_root / "modules",
]
for path in required:
if not path.exists():
raise click.ClickException(f"Invalid MCP bundle, missing: {path.name}")
server = MCPServer(
mcp_root=mcp_root,
name="doc-forge-mcp",
)
server.run()
# ---------------------------------------------------------------------
# serve
# ---------------------------------------------------------------------
@cli.command()
@click.option(
"--mkdocs-yml",
type=click.Path(path_type=Path),
default=Path("mkdocs.yml"),
)
def serve(mkdocs_yml: Path) -> None:
"""
Serve the documentation site with live-reload using MkDocs.
Args:
mkdocs_yml: Path to the mkdocs.yml configuration file.
"""
if not mkdocs_yml.exists():
raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}")
from mkdocs.commands.serve import serve as mkdocs_serve
host = "127.0.0.1"
port = 8000
url = f"http://{host}:{port}/"
click.echo(f"Serving documentation at {url}")
mkdocs_serve(config_file=str(mkdocs_yml))
# ---------------------------------------------------------------------
# entry point
# ---------------------------------------------------------------------
def main() -> None: def main() -> None:
""" """
CLI Entry point. CLI Entry point. Boots the click application.
""" """
cli() cli()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -1,109 +1 @@
from typing import Sequence def main() -> None: ...
from pathlib import Path
import click
@click.group()
def cli() -> None:
"""doc-forge command-line interface."""
@cli.command()
@click.option(
"--modules",
multiple=True,
help="Python module import paths to introspect",
)
@click.option(
"--project-name",
help="Project name (defaults to first module)",
)
def tree(
modules: Sequence[str],
project_name: str | None,
) -> None:
"""Show introspection tree."""
@cli.command()
@click.option(
"--module",
help="Python module import paths to document",
)
@click.option(
"--project-name",
help="Project name (defaults to first module)",
)
@click.option(
"--docs-dir",
type=click.Path(path_type=Path),
default=Path("docs"),
)
def generate(
module: str,
project_name: str | None,
docs_dir: Path,
) -> None:
"""Generate documentation source files using MkDocs renderer."""
@cli.command(name="generate-mcp")
@click.option(
"--module",
required=True,
help="Python module import path to document",
)
@click.option(
"--project-name",
help="Project name (defaults to first module)",
)
@click.option(
"--out-dir",
type=click.Path(path_type=Path),
default=Path("mcp_docs"),
)
def generate_mcp(
module: str,
project_name: str | None,
out_dir: Path,
) -> None:
"""
Generate MCP-compatible documentation resources for the specified module.
Args:
module: The primary module path to document.
project_name: Optional project name override.
out_dir: Directory where MCP resources will be written.
"""
@cli.command()
@click.option(
"--mkdocs-yml",
type=click.Path(path_type=Path),
default=Path("mkdocs.yml"),
)
def build(
mkdocs_yml: Path,
) -> None:
"""Build documentation using MkDocs."""
@cli.command()
@click.option(
"--mkdocs-yml",
type=click.Path(path_type=Path),
default=Path("mkdocs.yml"),
)
def serve(
mkdocs_yml: Path,
) -> None:
"""Serve documentation using MkDocs."""
@cli.command(name="serve-mcp")
def serve_mcp() -> None:
"""Serve MCP documentation."""
def main() -> None:
"""CLI entry point."""

47
docforge/cli/mcp_utils.py Normal file
View File

@@ -0,0 +1,47 @@
from pathlib import Path
import click
from docforge.loaders import GriffeLoader, discover_module_paths
from docforge.renderers import MCPRenderer
from docforge.servers import MCPServer
def generate_resources(module: str, project_name: str | None, out_dir: Path) -> None:
"""
Generate MCP-compatible documentation resources.
Args:
module: The dotted path of the primary module to document.
project_name: Optional override for the project name.
out_dir: Directory where the MCP JSON resources and nav will be written.
"""
loader = GriffeLoader()
discovered_paths = discover_module_paths(module)
project = loader.load_project(discovered_paths, project_name)
renderer = MCPRenderer()
renderer.generate_sources(project, out_dir)
def serve(mcp_root: Path) -> None:
"""
Serve MCP documentation from a pre-built bundle.
Args:
mcp_root: Path to the directory containing index.json, nav.json, and modules/.
"""
if not mcp_root.exists():
raise click.ClickException(f"mcp_docs directory not found: {mcp_root}")
required = [
mcp_root / "index.json",
mcp_root / "nav.json",
mcp_root / "modules",
]
for path in required:
if not path.exists():
raise click.ClickException(f"Invalid MCP bundle, missing: {path.name}")
server = MCPServer(
mcp_root=mcp_root,
name="doc-forge-mcp",
)
server.run()

View File

@@ -0,0 +1,4 @@
from pathlib import Path
def generate_resources(module: str, project_name: str | None, out_dir: Path) -> None: ...
def serve(mcp_root: Path) -> None: ...

View File

@@ -1,116 +0,0 @@
"""
This module contains the 'mkdocs' CLI command, which orchestrates the generation
of the main mkdocs.yml configuration file.
"""
from pathlib import Path
from importlib import resources
import click
import yaml
from docforge.nav import load_nav_spec
from docforge.nav import resolve_nav
from docforge.nav import MkDocsNavEmitter
def _load_template(template: Path | None) -> dict:
"""
Load a YAML template for mkdocs.yml. If no template is provided,
loads the built-in sample template.
Args:
template: Path to the template file, or None.
Returns:
The loaded template data as a dictionary.
"""
if template is not None:
if not template.exists():
raise click.FileError(str(template), hint="Template not found")
return yaml.safe_load(template.read_text(encoding="utf-8"))
# Load built-in default
text = (
resources.files("docforge.templates")
.joinpath("mkdocs.sample.yml")
.read_text(encoding="utf-8")
)
return yaml.safe_load(text)
@click.command("mkdocs")
@click.option(
"--site-name",
required=True,
help="MkDocs site_name (required)",
)
@click.option(
"--docs-dir",
type=click.Path(path_type=Path),
default=Path("docs"),
)
@click.option(
"--nav",
"nav_file",
type=click.Path(path_type=Path),
default=Path("docforge.nav.yml"),
)
@click.option(
"--template",
type=click.Path(path_type=Path),
default=None,
help="Override the built-in mkdocs template",
)
@click.option(
"--out",
type=click.Path(path_type=Path),
default=Path("mkdocs.yml"),
)
def mkdocs_cmd(
docs_dir: Path,
nav_file: Path,
template: Path | None,
out: Path,
site_name: str,
) -> None:
"""
Generate an mkdocs.yml configuration file by combining a template with
the navigation structure resolved from a docforge.nav.yml file.
Args:
docs_dir: Path to the directory containing documentation Markdown files.
nav_file: Path to the docforge.nav.yml specification.
template: Optional path to an mkdocs.yml template.
out: Path where the final mkdocs.yml will be written.
site_name: The name of the documentation site.
"""
if not nav_file.exists():
raise click.FileError(str(nav_file), hint="Nav spec not found")
# Load nav spec
spec = load_nav_spec(nav_file)
# Resolve nav
resolved = resolve_nav(spec, docs_dir)
# Emit mkdocs nav
nav_block = MkDocsNavEmitter().emit(resolved)
# Load template (user or built-in)
data = _load_template(template)
# Inject site_name
data["site_name"] = site_name
# Inject nav
data["nav"] = nav_block
# Write output
out.write_text(
yaml.safe_dump(data, sort_keys=False),
encoding="utf-8",
)
click.echo(f"mkdocs.yml written to {out}")

View File

@@ -1,45 +0,0 @@
from pathlib import Path
from typing import Any, Dict, Optional
import click
def _load_template(template: Optional[Path]) -> Dict[str, Any]:
...
@click.command("mkdocs")
@click.option(
"--site-name",
required=True,
help="MkDocs site_name (required)",
)
@click.option(
"--docs-dir",
type=click.Path(path_type=Path),
default=Path("docs"),
)
@click.option(
"--nav",
"nav_file",
type=click.Path(path_type=Path),
default=Path("docforge.nav.yml"),
)
@click.option(
"--template",
type=click.Path(path_type=Path),
default=None,
)
@click.option(
"--out",
type=click.Path(path_type=Path),
default=Path("mkdocs.yml"),
)
def mkdocs_cmd(
docs_dir: Path,
nav_file: Path,
template: Optional[Path],
out: Path,
site_name: str,
) -> None:
...

View File

@@ -0,0 +1,87 @@
from pathlib import Path
from importlib import resources
import click
import yaml
from docforge.loaders import GriffeLoader, discover_module_paths
from docforge.renderers import MkDocsRenderer
from docforge.nav import load_nav_spec, resolve_nav, MkDocsNavEmitter
def generate_sources(module: str, project_name: str | None, docs_dir: Path) -> None:
"""
Generate Markdown source files for the specified module.
Args:
module: The dotted path of the primary module to document.
project_name: Optional override for the project name.
docs_dir: Directory where the generated Markdown files will be written.
"""
loader = GriffeLoader()
discovered_paths = discover_module_paths(module)
project = loader.load_project(discovered_paths, project_name)
renderer = MkDocsRenderer()
renderer.generate_sources(project, docs_dir)
def generate_config(docs_dir: Path, nav_file: Path, template: Path | None, out: Path, site_name: str) -> None:
"""
Generate an mkdocs.yml configuration file.
Args:
docs_dir: Path to the directory containing documentation Markdown files.
nav_file: Path to the docforge.nav.yml specification.
template: Optional path to an mkdocs.yml template (overrides built-in).
out: Path where the final mkdocs.yml will be written.
site_name: The display name for the documentation site.
"""
if not nav_file.exists():
raise click.FileError(str(nav_file), hint="Nav spec not found")
spec = load_nav_spec(nav_file)
resolved = resolve_nav(spec, docs_dir)
nav_block = MkDocsNavEmitter().emit(resolved)
# Load template
if template is not None:
if not template.exists():
raise click.FileError(str(template), hint="Template not found")
data = yaml.safe_load(template.read_text(encoding="utf-8"))
else:
text = (
resources.files("docforge.templates")
.joinpath("mkdocs.sample.yml")
.read_text(encoding="utf-8")
)
data = yaml.safe_load(text)
data["site_name"] = site_name
data["nav"] = nav_block
out.write_text(yaml.safe_dump(data, sort_keys=False), encoding="utf-8")
def build(mkdocs_yml: Path) -> None:
"""
Build the documentation site using MkDocs.
Args:
mkdocs_yml: Path to the mkdocs.yml configuration file.
"""
if not mkdocs_yml.exists():
raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}")
from mkdocs.config import load_config
from mkdocs.commands.build import build as mkdocs_build
mkdocs_build(load_config(str(mkdocs_yml)))
def serve(mkdocs_yml: Path) -> None:
"""
Serve the documentation site with live-reload using MkDocs.
Args:
mkdocs_yml: Path to the mkdocs.yml configuration file.
"""
if not mkdocs_yml.exists():
raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}")
from mkdocs.commands.serve import serve as mkdocs_serve
mkdocs_serve(config_file=str(mkdocs_yml))

View File

@@ -0,0 +1,6 @@
from pathlib import Path
def generate_sources(module: str, project_name: str | None, docs_dir: Path) -> None: ...
def generate_config(docs_dir: Path, nav_file: Path, template: Path | None, out: Path, site_name: str) -> None: ...
def build(mkdocs_yml: Path) -> None: ...
def serve(mkdocs_yml: Path) -> None: ...

View File

@@ -134,6 +134,15 @@ class GriffeLoader:
# ------------------------- # -------------------------
def _convert_module(self, obj: Object) -> Module: def _convert_module(self, obj: Object) -> Module:
"""
Convert a Griffe Object (module) into a docforge Module.
Args:
obj: The Griffe Object representing the module.
Returns:
A populated Module instance.
"""
module = Module( module = Module(
path=obj.path, path=obj.path,
docstring=self._safe_docstring(obj), docstring=self._safe_docstring(obj),
@@ -148,6 +157,15 @@ class GriffeLoader:
return module return module
def _convert_object(self, obj: Object) -> DocObject: def _convert_object(self, obj: Object) -> DocObject:
"""
Recursively convert a Griffe Object into a DocObject hierarchy.
Args:
obj: The Griffe Object to convert.
Returns:
A DocObject instance.
"""
kind = obj.kind.value kind = obj.kind.value
signature = self._safe_signature(obj) signature = self._safe_signature(obj)
@@ -174,12 +192,30 @@ class GriffeLoader:
# ------------------------- # -------------------------
def _safe_docstring(self, obj: Object) -> Optional[str]: def _safe_docstring(self, obj: Object) -> Optional[str]:
"""
Safely retrieve the docstring value from a Griffe object.
Args:
obj: The Griffe Object to inspect.
Returns:
The raw docstring string, or None if missing or unresolvable.
"""
try: try:
return obj.docstring.value if obj.docstring else None return obj.docstring.value if obj.docstring else None
except AliasResolutionError: except AliasResolutionError:
return None return None
def _safe_signature(self, obj: Object) -> Optional[str]: def _safe_signature(self, obj: Object) -> Optional[str]:
"""
Safely retrieve the signature string from a Griffe object.
Args:
obj: The Griffe Object to inspect.
Returns:
The string representation of the signature, or None.
"""
try: try:
if hasattr(obj, "signature") and obj.signature: if hasattr(obj, "signature") and obj.signature:
return str(obj.signature) return str(obj.signature)

View File

@@ -78,6 +78,18 @@ def resolve_nav(
raise FileNotFoundError(docs_root) raise FileNotFoundError(docs_root)
def resolve_pattern(pattern: str) -> List[Path]: def resolve_pattern(pattern: str) -> List[Path]:
"""
Resolve a single glob pattern relative to the docs_root.
Args:
pattern: The glob pattern to resolve.
Returns:
A sorted list of matching Path objects.
Raises:
FileNotFoundError: If the pattern doesn't match any files.
"""
full = docs_root / pattern full = docs_root / pattern
matches = sorted( matches = sorted(
Path(p) for p in glob.glob(str(full), recursive=True) Path(p) for p in glob.glob(str(full), recursive=True)

View File

@@ -15,6 +15,10 @@ class MCPRenderer:
def generate_sources(self, project: Project, out_dir: Path) -> None: def generate_sources(self, project: Project, out_dir: Path) -> None:
""" """
Generate MCP-compatible JSON resources and navigation for the project. Generate MCP-compatible JSON resources and navigation for the project.
Args:
project: The project model to render.
out_dir: Target directory for the generated JSON files.
""" """
modules_dir = out_dir / "modules" modules_dir = out_dir / "modules"
modules_dir.mkdir(parents=True, exist_ok=True) modules_dir.mkdir(parents=True, exist_ok=True)
@@ -50,7 +54,11 @@ class MCPRenderer:
def _write_module(self, module: Module, modules_dir: Path) -> None: def _write_module(self, module: Module, modules_dir: Path) -> None:
""" """
Serialize a module into an MCP JSON resource. Serialize a module into an MCP JSON resource on disk.
Args:
module: The module instance to serialize.
modules_dir: The directory where the module JSON file should be written.
""" """
payload = { payload = {
"module": module.path, "module": module.path,
@@ -64,6 +72,12 @@ class MCPRenderer:
def _render_module(self, module: Module) -> Dict: def _render_module(self, module: Module) -> Dict:
""" """
Render a Module into MCP-friendly structured data. Render a Module into MCP-friendly structured data.
Args:
module: The module instance to render.
Returns:
A dictionary following the MCP documentation resource schema.
""" """
data: Dict = { data: Dict = {
"path": module.path, "path": module.path,
@@ -79,6 +93,12 @@ class MCPRenderer:
def _render_object(self, obj: DocObject) -> Dict: def _render_object(self, obj: DocObject) -> Dict:
""" """
Recursively render a DocObject into structured MCP data. Recursively render a DocObject into structured MCP data.
Args:
obj: The documented object (class, func, etc.) to render.
Returns:
A dictionary representing the object and its members.
""" """
data: Dict = { data: Dict = {
"name": obj.name, "name": obj.name,

View File

@@ -13,6 +13,13 @@ class MCPServer:
""" """
def __init__(self, mcp_root: Path, name: str) -> None: def __init__(self, mcp_root: Path, name: str) -> None:
"""
Initialize the MCPServer.
Args:
mcp_root: Path to the directory containing pre-built MCP JSON resources.
name: Name of the MCP server.
"""
self.mcp_root = mcp_root self.mcp_root = mcp_root
self.app = FastMCP(name) self.app = FastMCP(name)
@@ -24,6 +31,15 @@ class MCPServer:
# ------------------------------------------------------------------ # ------------------------------------------------------------------
def _read_json(self, path: Path) -> Any: def _read_json(self, path: Path) -> Any:
"""
Read and parse a JSON file, returning diagnostic errors if missing.
Args:
path: Path to the JSON file.
Returns:
The parsed JSON data or an error dictionary.
"""
if not path.exists(): if not path.exists():
return { return {
"error": "not_found", "error": "not_found",
@@ -36,6 +52,9 @@ class MCPServer:
# ------------------------------------------------------------------ # ------------------------------------------------------------------
def _register_resources(self) -> None: def _register_resources(self) -> None:
"""
Register MCP resources for index, nav, and individual modules.
"""
@self.app.resource("docs://index") @self.app.resource("docs://index")
def index(): def index():
return self._read_json(self.mcp_root / "index.json") return self._read_json(self.mcp_root / "index.json")
@@ -55,6 +74,9 @@ class MCPServer:
# ------------------------------------------------------------------ # ------------------------------------------------------------------
def _register_tools(self) -> None: def _register_tools(self) -> None:
"""
Register high-level MCP tools for diagnostics.
"""
@self.app.tool() @self.app.tool()
def ping() -> str: def ping() -> str:
return "pong" return "pong"

View File

@@ -0,0 +1,3 @@
# Commands
::: docforge.cli.commands

View File

@@ -0,0 +1,3 @@
# Mcp Utils
::: docforge.cli.mcp_utils

View File

@@ -1,3 +0,0 @@
# Mkdocs
::: docforge.cli.mkdocs

View File

@@ -0,0 +1,3 @@
# Mkdocs Utils
::: docforge.cli.mkdocs_utils

View File

@@ -0,0 +1,3 @@
# Servers
::: docforge.servers

View File

@@ -0,0 +1,3 @@
# Mcp Server
::: docforge.servers.mcp_server

View File

@@ -1,6 +1,6 @@
{ {
"project": "docforge", "project": "docforge",
"type": "docforge-model", "type": "docforge-model",
"modules_count": 20, "modules_count": 22,
"source": "docforge" "source": "docforge"
} }

View File

@@ -0,0 +1,370 @@
{
"module": "docforge.cli.commands",
"content": {
"path": "docforge.cli.commands",
"docstring": null,
"objects": {
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.commands.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.commands.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"Sequence": {
"name": "Sequence",
"kind": "alias",
"path": "docforge.cli.commands.Sequence",
"signature": "<bound method Alias.signature of Alias('Sequence', 'typing.Sequence')>",
"docstring": null
},
"Optional": {
"name": "Optional",
"kind": "alias",
"path": "docforge.cli.commands.Optional",
"signature": "<bound method Alias.signature of Alias('Optional', 'typing.Optional')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.commands.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.commands.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.commands.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"mkdocs_utils": {
"name": "mkdocs_utils",
"kind": "module",
"path": "docforge.cli.commands.mkdocs_utils",
"signature": "<bound method Alias.signature of Alias('mkdocs_utils', 'docforge.cli.mkdocs_utils')>",
"docstring": null,
"members": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.commands.mkdocs_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'docforge.cli.mkdocs_utils.Path')>",
"docstring": null
},
"resources": {
"name": "resources",
"kind": "alias",
"path": "docforge.cli.commands.mkdocs_utils.resources",
"signature": "<bound method Alias.signature of Alias('resources', 'docforge.cli.mkdocs_utils.resources')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.commands.mkdocs_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'docforge.cli.mkdocs_utils.click')>",
"docstring": null
},
"yaml": {
"name": "yaml",
"kind": "alias",
"path": "docforge.cli.commands.mkdocs_utils.yaml",
"signature": "<bound method Alias.signature of Alias('yaml', 'docforge.cli.mkdocs_utils.yaml')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.commands.mkdocs_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.cli.mkdocs_utils.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.cli.mkdocs_utils.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MkDocsRenderer": {
"name": "MkDocsRenderer",
"kind": "class",
"path": "docforge.cli.commands.mkdocs_utils.MkDocsRenderer",
"signature": "<bound method Alias.signature of Alias('MkDocsRenderer', 'docforge.cli.mkdocs_utils.MkDocsRenderer')>",
"docstring": "Renderer that generates Markdown source files formatted for the MkDocs\n'mkdocstrings' plugin.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.commands.mkdocs_utils.MkDocsRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.MkDocsRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.generate_sources')>",
"docstring": "Produce a set of Markdown files in the output directory based on the\nprovided Project models.\n\nArgs:\n project: The project models to render.\n out_dir: Target directory for documentation files."
}
}
},
"load_nav_spec": {
"name": "load_nav_spec",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.load_nav_spec",
"signature": "<bound method Alias.signature of Alias('load_nav_spec', 'docforge.cli.mkdocs_utils.load_nav_spec')>",
"docstring": "Utility function to load a NavSpec from a file.\n\nArgs:\n path: Path to the navigation specification file.\n\nReturns:\n A loaded NavSpec instance."
},
"resolve_nav": {
"name": "resolve_nav",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.resolve_nav",
"signature": "<bound method Alias.signature of Alias('resolve_nav', 'docforge.cli.mkdocs_utils.resolve_nav')>",
"docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist."
},
"MkDocsNavEmitter": {
"name": "MkDocsNavEmitter",
"kind": "class",
"path": "docforge.cli.commands.mkdocs_utils.MkDocsNavEmitter",
"signature": "<bound method Alias.signature of Alias('MkDocsNavEmitter', 'docforge.cli.mkdocs_utils.MkDocsNavEmitter')>",
"docstring": "Emitter responsible for transforming a ResolvedNav into an MkDocs-compatible\nnavigation structure.",
"members": {
"emit": {
"name": "emit",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.MkDocsNavEmitter.emit",
"signature": "<bound method Alias.signature of Alias('emit', 'docforge.nav.mkdocs.MkDocsNavEmitter.emit')>",
"docstring": "Generate a list of navigation entries for mkdocs.yml.\n\nArgs:\n nav: The resolved navigation data.\n\nReturns:\n A list of dictionary mappings representing the MkDocs navigation."
}
}
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.cli.mkdocs_utils.generate_sources')>",
"docstring": "Generate Markdown source files for the specified module.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n docs_dir: Directory where the generated Markdown files will be written."
},
"generate_config": {
"name": "generate_config",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.generate_config",
"signature": "<bound method Alias.signature of Alias('generate_config', 'docforge.cli.mkdocs_utils.generate_config')>",
"docstring": "Generate an mkdocs.yml configuration file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template (overrides built-in).\n out: Path where the final mkdocs.yml will be written.\n site_name: The display name for the documentation site."
},
"build": {
"name": "build",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.build",
"signature": "<bound method Alias.signature of Alias('build', 'docforge.cli.mkdocs_utils.build')>",
"docstring": "Build the documentation site using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.serve",
"signature": "<bound method Alias.signature of Alias('serve', 'docforge.cli.mkdocs_utils.serve')>",
"docstring": "Serve the documentation site with live-reload using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
}
}
},
"mcp_utils": {
"name": "mcp_utils",
"kind": "module",
"path": "docforge.cli.commands.mcp_utils",
"signature": "<bound method Alias.signature of Alias('mcp_utils', 'docforge.cli.mcp_utils')>",
"docstring": null,
"members": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.commands.mcp_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'docforge.cli.mcp_utils.Path')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.commands.mcp_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'docforge.cli.mcp_utils.click')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.commands.mcp_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.cli.mcp_utils.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.cli.mcp_utils.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MCPRenderer": {
"name": "MCPRenderer",
"kind": "class",
"path": "docforge.cli.commands.mcp_utils.MCPRenderer",
"signature": "<bound method Alias.signature of Alias('MCPRenderer', 'docforge.cli.mcp_utils.MCPRenderer')>",
"docstring": "Renderer that emits MCP-native JSON resources from docforge models.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.commands.mcp_utils.MCPRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mcp_renderer.MCPRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.MCPRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mcp_renderer.MCPRenderer.generate_sources')>",
"docstring": "Generate MCP-compatible JSON resources and navigation for the project.\n\nArgs:\n project: The project model to render.\n out_dir: Target directory for the generated JSON files."
}
}
},
"MCPServer": {
"name": "MCPServer",
"kind": "class",
"path": "docforge.cli.commands.mcp_utils.MCPServer",
"signature": "<bound method Alias.signature of Alias('MCPServer', 'docforge.cli.mcp_utils.MCPServer')>",
"docstring": "MCP server for serving a pre-built MCP documentation bundle.",
"members": {
"mcp_root": {
"name": "mcp_root",
"kind": "attribute",
"path": "docforge.cli.commands.mcp_utils.MCPServer.mcp_root",
"signature": "<bound method Alias.signature of Alias('mcp_root', 'docforge.servers.mcp_server.MCPServer.mcp_root')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "docforge.cli.commands.mcp_utils.MCPServer.app",
"signature": "<bound method Alias.signature of Alias('app', 'docforge.servers.mcp_server.MCPServer.app')>",
"docstring": null
},
"run": {
"name": "run",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.MCPServer.run",
"signature": "<bound method Alias.signature of Alias('run', 'docforge.servers.mcp_server.MCPServer.run')>",
"docstring": "Start the MCP server.\n\nArgs:\n transport: MCP transport (default: streamable-http)"
}
}
},
"generate_resources": {
"name": "generate_resources",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.generate_resources",
"signature": "<bound method Alias.signature of Alias('generate_resources', 'docforge.cli.mcp_utils.generate_resources')>",
"docstring": "Generate MCP-compatible documentation resources.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n out_dir: Directory where the MCP JSON resources and nav will be written."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.serve",
"signature": "<bound method Alias.signature of Alias('serve', 'docforge.cli.mcp_utils.serve')>",
"docstring": "Serve MCP documentation from a pre-built bundle.\n\nArgs:\n mcp_root: Path to the directory containing index.json, nav.json, and modules/."
}
}
},
"cli": {
"name": "cli",
"kind": "attribute",
"path": "docforge.cli.commands.cli",
"signature": null,
"docstring": null
},
"build": {
"name": "build",
"kind": "function",
"path": "docforge.cli.commands.build",
"signature": "<bound method Function.signature of Function('build', 18, 89)>",
"docstring": "Build documentation (MkDocs site or MCP resources).\n\nThis command orchestrates the full build process:\n1. Introspects the code (Griffe)\n2. Renders sources (MkDocs Markdown or MCP JSON)\n3. (MkDocs only) Generates config and runs the final site build.\n\nArgs:\n mcp: Use the MCP documentation builder.\n mkdocs: Use the MkDocs documentation builder.\n module: The dotted path of the module to document.\n project_name: Optional override for the project name.\n site_name: (MkDocs) The site display name. Defaults to module name.\n docs_dir: (MkDocs) Target directory for Markdown sources.\n nav_file: (MkDocs) Path to the docforge.nav.yml specification.\n template: (MkDocs) Optional custom mkdocs.yml template.\n mkdocs_yml: (MkDocs) Target path for the generated mkdocs.yml.\n out_dir: (MCP) Target directory for MCP JSON resources."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.commands.serve",
"signature": "<bound method Function.signature of Function('serve', 92, 120)>",
"docstring": "Serve documentation (MkDocs or MCP).\n\nArgs:\n mcp: Serve MCP resources via an MCP server.\n mkdocs: Serve the MkDocs site using the built-in development server.\n mkdocs_yml: (MkDocs) Path to the mkdocs.yml configuration.\n out_dir: (MCP) Path to the mcp_docs/ directory."
},
"tree": {
"name": "tree",
"kind": "function",
"path": "docforge.cli.commands.tree",
"signature": "<bound method Function.signature of Function('tree', 123, 153)>",
"docstring": "Visualize the project structure in the terminal.\n\nArgs:\n modules: List of module import paths to recursively introspect.\n project_name: Optional override for the project name shown at the root."
},
"Group": {
"name": "Group",
"kind": "alias",
"path": "docforge.cli.commands.Group",
"signature": "<bound method Alias.signature of Alias('Group', 'click.core.Group')>",
"docstring": null
},
"Any": {
"name": "Any",
"kind": "alias",
"path": "docforge.cli.commands.Any",
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
"docstring": null
}
}
}
}

View File

@@ -2,61 +2,142 @@
"module": "docforge.cli", "module": "docforge.cli",
"content": { "content": {
"path": "docforge.cli", "path": "docforge.cli",
"docstring": "# CLI Layer\n\nThe `docforge.cli` package provides the command-line interface for interacting\nwith doc-forge.\n\n## Available Commands\n\n- **tree**: Visualize the introspected project structure.\n- **generate**: Create Markdown source files from Python code.\n- **mkdocs**: Generate the primary `mkdocs.yml` configuration.\n- **build**: Build the final documentation site.\n- **serve**: Launch a local development server with live-reloading.", "docstring": "# CLI Layer\n\nThe `docforge.cli` package provides the command-line interface for interacting\nwith doc-forge.\n\n## Available Commands\n\n- **build**: Build documentation (MkDocs site or MCP resources).\n- **serve**: Serve documentation (MkDocs or MCP).\n- **tree**: Visualize the introspected project structure.",
"objects": { "objects": {
"main": { "main": {
"name": "main", "name": "main",
"kind": "module", "kind": "module",
"path": "docforge.cli.main", "path": "docforge.cli.main",
"signature": null, "signature": null,
"docstring": "Main entry point for the doc-forge CLI. This module defines the core command\ngroup and the 'tree', 'generate', 'build', and 'serve' commands.", "docstring": "Main entry point for the doc-forge CLI. This module delegates all command\nexecution to docforge.cli.commands.",
"members": { "members": {
"cli": {
"name": "cli",
"kind": "attribute",
"path": "docforge.cli.main.cli",
"signature": "<bound method Alias.signature of Alias('cli', 'docforge.cli.commands.cli')>",
"docstring": null
},
"main": {
"name": "main",
"kind": "function",
"path": "docforge.cli.main.main",
"signature": "<bound method Function.signature of Function('main', 7, 11)>",
"docstring": "CLI Entry point. Boots the click application."
}
}
},
"commands": {
"name": "commands",
"kind": "module",
"path": "docforge.cli.commands",
"signature": null,
"docstring": null,
"members": {
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.commands.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"Path": { "Path": {
"name": "Path", "name": "Path",
"kind": "alias", "kind": "alias",
"path": "docforge.cli.main.Path", "path": "docforge.cli.commands.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>", "signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null "docstring": null
}, },
"Sequence": { "Sequence": {
"name": "Sequence", "name": "Sequence",
"kind": "alias", "kind": "alias",
"path": "docforge.cli.main.Sequence", "path": "docforge.cli.commands.Sequence",
"signature": "<bound method Alias.signature of Alias('Sequence', 'typing.Sequence')>", "signature": "<bound method Alias.signature of Alias('Sequence', 'typing.Sequence')>",
"docstring": null "docstring": null
}, },
"Optional": { "Optional": {
"name": "Optional", "name": "Optional",
"kind": "alias", "kind": "alias",
"path": "docforge.cli.main.Optional", "path": "docforge.cli.commands.Optional",
"signature": "<bound method Alias.signature of Alias('Optional', 'typing.Optional')>", "signature": "<bound method Alias.signature of Alias('Optional', 'typing.Optional')>",
"docstring": null "docstring": null
}, },
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.main.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"GriffeLoader": { "GriffeLoader": {
"name": "GriffeLoader", "name": "GriffeLoader",
"kind": "class", "kind": "class",
"path": "docforge.cli.main.GriffeLoader", "path": "docforge.cli.commands.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>", "signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.", "docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": { "members": {
"load_project": { "load_project": {
"name": "load_project", "name": "load_project",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.GriffeLoader.load_project", "path": "docforge.cli.commands.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>", "signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules." "docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
}, },
"load_module": { "load_module": {
"name": "load_module", "name": "load_module",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.GriffeLoader.load_module", "path": "docforge.cli.commands.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"mkdocs_utils": {
"name": "mkdocs_utils",
"kind": "module",
"path": "docforge.cli.commands.mkdocs_utils",
"signature": "<bound method Alias.signature of Alias('mkdocs_utils', 'docforge.cli.mkdocs_utils')>",
"docstring": null,
"members": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.commands.mkdocs_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'docforge.cli.mkdocs_utils.Path')>",
"docstring": null
},
"resources": {
"name": "resources",
"kind": "alias",
"path": "docforge.cli.commands.mkdocs_utils.resources",
"signature": "<bound method Alias.signature of Alias('resources', 'docforge.cli.mkdocs_utils.resources')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.commands.mkdocs_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'docforge.cli.mkdocs_utils.click')>",
"docstring": null
},
"yaml": {
"name": "yaml",
"kind": "alias",
"path": "docforge.cli.commands.mkdocs_utils.yaml",
"signature": "<bound method Alias.signature of Alias('yaml', 'docforge.cli.mkdocs_utils.yaml')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.commands.mkdocs_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.cli.mkdocs_utils.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>", "signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance." "docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
} }
@@ -65,213 +146,522 @@
"discover_module_paths": { "discover_module_paths": {
"name": "discover_module_paths", "name": "discover_module_paths",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.discover_module_paths", "path": "docforge.cli.commands.mkdocs_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.loaders.discover_module_paths')>", "signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.cli.mkdocs_utils.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths." "docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
}, },
"MkDocsRenderer": { "MkDocsRenderer": {
"name": "MkDocsRenderer", "name": "MkDocsRenderer",
"kind": "class", "kind": "class",
"path": "docforge.cli.main.MkDocsRenderer", "path": "docforge.cli.commands.mkdocs_utils.MkDocsRenderer",
"signature": "<bound method Alias.signature of Alias('MkDocsRenderer', 'docforge.renderers.MkDocsRenderer')>", "signature": "<bound method Alias.signature of Alias('MkDocsRenderer', 'docforge.cli.mkdocs_utils.MkDocsRenderer')>",
"docstring": "Renderer that generates Markdown source files formatted for the MkDocs\n'mkdocstrings' plugin.", "docstring": "Renderer that generates Markdown source files formatted for the MkDocs\n'mkdocstrings' plugin.",
"members": { "members": {
"name": { "name": {
"name": "name", "name": "name",
"kind": "attribute", "kind": "attribute",
"path": "docforge.cli.main.MkDocsRenderer.name", "path": "docforge.cli.commands.mkdocs_utils.MkDocsRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.name')>", "signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.name')>",
"docstring": null "docstring": null
}, },
"generate_sources": { "generate_sources": {
"name": "generate_sources", "name": "generate_sources",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.MkDocsRenderer.generate_sources", "path": "docforge.cli.commands.mkdocs_utils.MkDocsRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.generate_sources')>", "signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.generate_sources')>",
"docstring": "Produce a set of Markdown files in the output directory based on the\nprovided Project models.\n\nArgs:\n project: The project models to render.\n out_dir: Target directory for documentation files." "docstring": "Produce a set of Markdown files in the output directory based on the\nprovided Project models.\n\nArgs:\n project: The project models to render.\n out_dir: Target directory for documentation files."
} }
} }
}, },
"load_nav_spec": {
"name": "load_nav_spec",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.load_nav_spec",
"signature": "<bound method Alias.signature of Alias('load_nav_spec', 'docforge.cli.mkdocs_utils.load_nav_spec')>",
"docstring": "Utility function to load a NavSpec from a file.\n\nArgs:\n path: Path to the navigation specification file.\n\nReturns:\n A loaded NavSpec instance."
},
"resolve_nav": {
"name": "resolve_nav",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.resolve_nav",
"signature": "<bound method Alias.signature of Alias('resolve_nav', 'docforge.cli.mkdocs_utils.resolve_nav')>",
"docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist."
},
"MkDocsNavEmitter": {
"name": "MkDocsNavEmitter",
"kind": "class",
"path": "docforge.cli.commands.mkdocs_utils.MkDocsNavEmitter",
"signature": "<bound method Alias.signature of Alias('MkDocsNavEmitter', 'docforge.cli.mkdocs_utils.MkDocsNavEmitter')>",
"docstring": "Emitter responsible for transforming a ResolvedNav into an MkDocs-compatible\nnavigation structure.",
"members": {
"emit": {
"name": "emit",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.MkDocsNavEmitter.emit",
"signature": "<bound method Alias.signature of Alias('emit', 'docforge.nav.mkdocs.MkDocsNavEmitter.emit')>",
"docstring": "Generate a list of navigation entries for mkdocs.yml.\n\nArgs:\n nav: The resolved navigation data.\n\nReturns:\n A list of dictionary mappings representing the MkDocs navigation."
}
}
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.cli.mkdocs_utils.generate_sources')>",
"docstring": "Generate Markdown source files for the specified module.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n docs_dir: Directory where the generated Markdown files will be written."
},
"generate_config": {
"name": "generate_config",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.generate_config",
"signature": "<bound method Alias.signature of Alias('generate_config', 'docforge.cli.mkdocs_utils.generate_config')>",
"docstring": "Generate an mkdocs.yml configuration file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template (overrides built-in).\n out: Path where the final mkdocs.yml will be written.\n site_name: The display name for the documentation site."
},
"build": {
"name": "build",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.build",
"signature": "<bound method Alias.signature of Alias('build', 'docforge.cli.mkdocs_utils.build')>",
"docstring": "Build the documentation site using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.commands.mkdocs_utils.serve",
"signature": "<bound method Alias.signature of Alias('serve', 'docforge.cli.mkdocs_utils.serve')>",
"docstring": "Serve the documentation site with live-reload using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
}
}
},
"mcp_utils": {
"name": "mcp_utils",
"kind": "module",
"path": "docforge.cli.commands.mcp_utils",
"signature": "<bound method Alias.signature of Alias('mcp_utils', 'docforge.cli.mcp_utils')>",
"docstring": null,
"members": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.commands.mcp_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'docforge.cli.mcp_utils.Path')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.commands.mcp_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'docforge.cli.mcp_utils.click')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.commands.mcp_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.cli.mcp_utils.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.commands.mcp_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.cli.mcp_utils.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MCPRenderer": { "MCPRenderer": {
"name": "MCPRenderer", "name": "MCPRenderer",
"kind": "class", "kind": "class",
"path": "docforge.cli.main.MCPRenderer", "path": "docforge.cli.commands.mcp_utils.MCPRenderer",
"signature": "<bound method Alias.signature of Alias('MCPRenderer', 'docforge.renderers.MCPRenderer')>", "signature": "<bound method Alias.signature of Alias('MCPRenderer', 'docforge.cli.mcp_utils.MCPRenderer')>",
"docstring": "Renderer that emits MCP-native JSON resources from docforge models.", "docstring": "Renderer that emits MCP-native JSON resources from docforge models.",
"members": { "members": {
"name": { "name": {
"name": "name", "name": "name",
"kind": "attribute", "kind": "attribute",
"path": "docforge.cli.main.MCPRenderer.name", "path": "docforge.cli.commands.mcp_utils.MCPRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mcp_renderer.MCPRenderer.name')>", "signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mcp_renderer.MCPRenderer.name')>",
"docstring": null "docstring": null
}, },
"generate_sources": { "generate_sources": {
"name": "generate_sources", "name": "generate_sources",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.MCPRenderer.generate_sources", "path": "docforge.cli.commands.mcp_utils.MCPRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mcp_renderer.MCPRenderer.generate_sources')>", "signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mcp_renderer.MCPRenderer.generate_sources')>",
"docstring": "Generate MCP-compatible JSON resources and navigation for the project." "docstring": "Generate MCP-compatible JSON resources and navigation for the project.\n\nArgs:\n project: The project model to render.\n out_dir: Target directory for the generated JSON files."
} }
} }
}, },
"mkdocs_cmd": { "MCPServer": {
"name": "mkdocs_cmd", "name": "MCPServer",
"kind": "function", "kind": "class",
"path": "docforge.cli.main.mkdocs_cmd", "path": "docforge.cli.commands.mcp_utils.MCPServer",
"signature": "<bound method Alias.signature of Alias('mkdocs_cmd', 'docforge.cli.mkdocs.mkdocs_cmd')>", "signature": "<bound method Alias.signature of Alias('MCPServer', 'docforge.cli.mcp_utils.MCPServer')>",
"docstring": "Generate an mkdocs.yml configuration file by combining a template with\nthe navigation structure resolved from a docforge.nav.yml file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template.\n out: Path where the final mkdocs.yml will be written.\n site_name: The name of the documentation site." "docstring": "MCP server for serving a pre-built MCP documentation bundle.",
"members": {
"mcp_root": {
"name": "mcp_root",
"kind": "attribute",
"path": "docforge.cli.commands.mcp_utils.MCPServer.mcp_root",
"signature": "<bound method Alias.signature of Alias('mcp_root', 'docforge.servers.mcp_server.MCPServer.mcp_root')>",
"docstring": null
}, },
"cli": { "app": {
"name": "cli", "name": "app",
"kind": "function", "kind": "attribute",
"path": "docforge.cli.main.cli", "path": "docforge.cli.commands.mcp_utils.MCPServer.app",
"signature": "<bound method Function.signature of Function('cli', 16, 22)>", "signature": "<bound method Alias.signature of Alias('app', 'docforge.servers.mcp_server.MCPServer.app')>",
"docstring": "doc-forge CLI: A tool for introspecting Python projects and generating\ndocumentation." "docstring": null
}, },
"tree": { "run": {
"name": "tree", "name": "run",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.tree", "path": "docforge.cli.commands.mcp_utils.MCPServer.run",
"signature": "<bound method Function.signature of Function('tree', 31, 62)>", "signature": "<bound method Alias.signature of Alias('run', 'docforge.servers.mcp_server.MCPServer.run')>",
"docstring": "Visualize the project structure including modules and their members.\n\nArgs:\n modules: List of module paths to introspect.\n project_name: Optional project name override." "docstring": "Start the MCP server.\n\nArgs:\n transport: MCP transport (default: streamable-http)"
}
}
}, },
"generate": { "generate_resources": {
"name": "generate", "name": "generate_resources",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.generate", "path": "docforge.cli.commands.mcp_utils.generate_resources",
"signature": "<bound method Function.signature of Function('generate', 78, 118)>", "signature": "<bound method Alias.signature of Alias('generate_resources', 'docforge.cli.mcp_utils.generate_resources')>",
"docstring": "Generate Markdown source files for the specified module.\n\nArgs:\n module: The primary module path to document.\n project_name: Optional project name override.\n docs_dir: Directory where documentation sources will be written." "docstring": "Generate MCP-compatible documentation resources.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n out_dir: Directory where the MCP JSON resources and nav will be written."
},
"generate_mcp": {
"name": "generate_mcp",
"kind": "function",
"path": "docforge.cli.main.generate_mcp",
"signature": "<bound method Function.signature of Function('generate_mcp', 125, 164)>",
"docstring": "Generate MCP-compatible documentation resources for the specified module.\n\nArgs:\n module: The primary module path to document.\n project_name: Optional project name override.\n out_dir: Directory where MCP resources will be written."
},
"build": {
"name": "build",
"kind": "function",
"path": "docforge.cli.main.build",
"signature": "<bound method Function.signature of Function('build', 171, 192)>",
"docstring": "Build the documentation site using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
},
"serve_mcp": {
"name": "serve_mcp",
"kind": "function",
"path": "docforge.cli.main.serve_mcp",
"signature": "<bound method Function.signature of Function('serve_mcp', 199, 226)>",
"docstring": "Serve MCP documentation from the local mcp_docs directory."
}, },
"serve": { "serve": {
"name": "serve", "name": "serve",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.serve", "path": "docforge.cli.commands.mcp_utils.serve",
"signature": "<bound method Function.signature of Function('serve', 233, 256)>", "signature": "<bound method Alias.signature of Alias('serve', 'docforge.cli.mcp_utils.serve')>",
"docstring": "Serve the documentation site with live-reload using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file." "docstring": "Serve MCP documentation from a pre-built bundle.\n\nArgs:\n mcp_root: Path to the directory containing index.json, nav.json, and modules/."
},
"main": {
"name": "main",
"kind": "function",
"path": "docforge.cli.main.main",
"signature": "<bound method Function.signature of Function('main', 263, 267)>",
"docstring": "CLI Entry point."
} }
} }
}, },
"mkdocs": { "cli": {
"name": "mkdocs", "name": "cli",
"kind": "module", "kind": "attribute",
"path": "docforge.cli.mkdocs", "path": "docforge.cli.commands.cli",
"signature": null, "signature": null,
"docstring": "This module contains the 'mkdocs' CLI command, which orchestrates the generation\nof the main mkdocs.yml configuration file.", "docstring": null
},
"build": {
"name": "build",
"kind": "function",
"path": "docforge.cli.commands.build",
"signature": "<bound method Function.signature of Function('build', 18, 89)>",
"docstring": "Build documentation (MkDocs site or MCP resources).\n\nThis command orchestrates the full build process:\n1. Introspects the code (Griffe)\n2. Renders sources (MkDocs Markdown or MCP JSON)\n3. (MkDocs only) Generates config and runs the final site build.\n\nArgs:\n mcp: Use the MCP documentation builder.\n mkdocs: Use the MkDocs documentation builder.\n module: The dotted path of the module to document.\n project_name: Optional override for the project name.\n site_name: (MkDocs) The site display name. Defaults to module name.\n docs_dir: (MkDocs) Target directory for Markdown sources.\n nav_file: (MkDocs) Path to the docforge.nav.yml specification.\n template: (MkDocs) Optional custom mkdocs.yml template.\n mkdocs_yml: (MkDocs) Target path for the generated mkdocs.yml.\n out_dir: (MCP) Target directory for MCP JSON resources."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.commands.serve",
"signature": "<bound method Function.signature of Function('serve', 92, 120)>",
"docstring": "Serve documentation (MkDocs or MCP).\n\nArgs:\n mcp: Serve MCP resources via an MCP server.\n mkdocs: Serve the MkDocs site using the built-in development server.\n mkdocs_yml: (MkDocs) Path to the mkdocs.yml configuration.\n out_dir: (MCP) Path to the mcp_docs/ directory."
},
"tree": {
"name": "tree",
"kind": "function",
"path": "docforge.cli.commands.tree",
"signature": "<bound method Function.signature of Function('tree', 123, 153)>",
"docstring": "Visualize the project structure in the terminal.\n\nArgs:\n modules: List of module import paths to recursively introspect.\n project_name: Optional override for the project name shown at the root."
},
"Group": {
"name": "Group",
"kind": "alias",
"path": "docforge.cli.commands.Group",
"signature": "<bound method Alias.signature of Alias('Group', 'click.core.Group')>",
"docstring": null
},
"Any": {
"name": "Any",
"kind": "alias",
"path": "docforge.cli.commands.Any",
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
"docstring": null
}
}
},
"mcp_utils": {
"name": "mcp_utils",
"kind": "module",
"path": "docforge.cli.mcp_utils",
"signature": null,
"docstring": null,
"members": { "members": {
"Path": { "Path": {
"name": "Path", "name": "Path",
"kind": "alias", "kind": "alias",
"path": "docforge.cli.mkdocs.Path", "path": "docforge.cli.mcp_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.mcp_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.mcp_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.mcp_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.mcp_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.mcp_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.loaders.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MCPRenderer": {
"name": "MCPRenderer",
"kind": "class",
"path": "docforge.cli.mcp_utils.MCPRenderer",
"signature": "<bound method Alias.signature of Alias('MCPRenderer', 'docforge.renderers.MCPRenderer')>",
"docstring": "Renderer that emits MCP-native JSON resources from docforge models.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.mcp_utils.MCPRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mcp_renderer.MCPRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.mcp_utils.MCPRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mcp_renderer.MCPRenderer.generate_sources')>",
"docstring": "Generate MCP-compatible JSON resources and navigation for the project.\n\nArgs:\n project: The project model to render.\n out_dir: Target directory for the generated JSON files."
}
}
},
"MCPServer": {
"name": "MCPServer",
"kind": "class",
"path": "docforge.cli.mcp_utils.MCPServer",
"signature": "<bound method Alias.signature of Alias('MCPServer', 'docforge.servers.MCPServer')>",
"docstring": "MCP server for serving a pre-built MCP documentation bundle.",
"members": {
"mcp_root": {
"name": "mcp_root",
"kind": "attribute",
"path": "docforge.cli.mcp_utils.MCPServer.mcp_root",
"signature": "<bound method Alias.signature of Alias('mcp_root', 'docforge.servers.mcp_server.MCPServer.mcp_root')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "docforge.cli.mcp_utils.MCPServer.app",
"signature": "<bound method Alias.signature of Alias('app', 'docforge.servers.mcp_server.MCPServer.app')>",
"docstring": null
},
"run": {
"name": "run",
"kind": "function",
"path": "docforge.cli.mcp_utils.MCPServer.run",
"signature": "<bound method Alias.signature of Alias('run', 'docforge.servers.mcp_server.MCPServer.run')>",
"docstring": "Start the MCP server.\n\nArgs:\n transport: MCP transport (default: streamable-http)"
}
}
},
"generate_resources": {
"name": "generate_resources",
"kind": "function",
"path": "docforge.cli.mcp_utils.generate_resources",
"signature": "<bound method Function.signature of Function('generate_resources', 7, 21)>",
"docstring": "Generate MCP-compatible documentation resources.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n out_dir: Directory where the MCP JSON resources and nav will be written."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.mcp_utils.serve",
"signature": "<bound method Function.signature of Function('serve', 23, 47)>",
"docstring": "Serve MCP documentation from a pre-built bundle.\n\nArgs:\n mcp_root: Path to the directory containing index.json, nav.json, and modules/."
}
}
},
"mkdocs_utils": {
"name": "mkdocs_utils",
"kind": "module",
"path": "docforge.cli.mkdocs_utils",
"signature": null,
"docstring": null,
"members": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>", "signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null "docstring": null
}, },
"resources": { "resources": {
"name": "resources", "name": "resources",
"kind": "alias", "kind": "alias",
"path": "docforge.cli.mkdocs.resources", "path": "docforge.cli.mkdocs_utils.resources",
"signature": "<bound method Alias.signature of Alias('resources', 'importlib.resources')>", "signature": "<bound method Alias.signature of Alias('resources', 'importlib.resources')>",
"docstring": null "docstring": null
}, },
"click": { "click": {
"name": "click", "name": "click",
"kind": "alias", "kind": "alias",
"path": "docforge.cli.mkdocs.click", "path": "docforge.cli.mkdocs_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>", "signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null "docstring": null
}, },
"yaml": { "yaml": {
"name": "yaml", "name": "yaml",
"kind": "alias", "kind": "alias",
"path": "docforge.cli.mkdocs.yaml", "path": "docforge.cli.mkdocs_utils.yaml",
"signature": "<bound method Alias.signature of Alias('yaml', 'yaml')>", "signature": "<bound method Alias.signature of Alias('yaml', 'yaml')>",
"docstring": null "docstring": null
}, },
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.mkdocs_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.loaders.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MkDocsRenderer": {
"name": "MkDocsRenderer",
"kind": "class",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer",
"signature": "<bound method Alias.signature of Alias('MkDocsRenderer', 'docforge.renderers.MkDocsRenderer')>",
"docstring": "Renderer that generates Markdown source files formatted for the MkDocs\n'mkdocstrings' plugin.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.generate_sources')>",
"docstring": "Produce a set of Markdown files in the output directory based on the\nprovided Project models.\n\nArgs:\n project: The project models to render.\n out_dir: Target directory for documentation files."
}
}
},
"load_nav_spec": { "load_nav_spec": {
"name": "load_nav_spec", "name": "load_nav_spec",
"kind": "function", "kind": "function",
"path": "docforge.cli.mkdocs.load_nav_spec", "path": "docforge.cli.mkdocs_utils.load_nav_spec",
"signature": "<bound method Alias.signature of Alias('load_nav_spec', 'docforge.nav.load_nav_spec')>", "signature": "<bound method Alias.signature of Alias('load_nav_spec', 'docforge.nav.load_nav_spec')>",
"docstring": "Utility function to load a NavSpec from a file.\n\nArgs:\n path: Path to the navigation specification file.\n\nReturns:\n A loaded NavSpec instance." "docstring": "Utility function to load a NavSpec from a file.\n\nArgs:\n path: Path to the navigation specification file.\n\nReturns:\n A loaded NavSpec instance."
}, },
"resolve_nav": { "resolve_nav": {
"name": "resolve_nav", "name": "resolve_nav",
"kind": "function", "kind": "function",
"path": "docforge.cli.mkdocs.resolve_nav", "path": "docforge.cli.mkdocs_utils.resolve_nav",
"signature": "<bound method Alias.signature of Alias('resolve_nav', 'docforge.nav.resolve_nav')>", "signature": "<bound method Alias.signature of Alias('resolve_nav', 'docforge.nav.resolve_nav')>",
"docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist." "docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist."
}, },
"MkDocsNavEmitter": { "MkDocsNavEmitter": {
"name": "MkDocsNavEmitter", "name": "MkDocsNavEmitter",
"kind": "class", "kind": "class",
"path": "docforge.cli.mkdocs.MkDocsNavEmitter", "path": "docforge.cli.mkdocs_utils.MkDocsNavEmitter",
"signature": "<bound method Alias.signature of Alias('MkDocsNavEmitter', 'docforge.nav.MkDocsNavEmitter')>", "signature": "<bound method Alias.signature of Alias('MkDocsNavEmitter', 'docforge.nav.MkDocsNavEmitter')>",
"docstring": "Emitter responsible for transforming a ResolvedNav into an MkDocs-compatible\nnavigation structure.", "docstring": "Emitter responsible for transforming a ResolvedNav into an MkDocs-compatible\nnavigation structure.",
"members": { "members": {
"emit": { "emit": {
"name": "emit", "name": "emit",
"kind": "function", "kind": "function",
"path": "docforge.cli.mkdocs.MkDocsNavEmitter.emit", "path": "docforge.cli.mkdocs_utils.MkDocsNavEmitter.emit",
"signature": "<bound method Alias.signature of Alias('emit', 'docforge.nav.mkdocs.MkDocsNavEmitter.emit')>", "signature": "<bound method Alias.signature of Alias('emit', 'docforge.nav.mkdocs.MkDocsNavEmitter.emit')>",
"docstring": "Generate a list of navigation entries for mkdocs.yml.\n\nArgs:\n nav: The resolved navigation data.\n\nReturns:\n A list of dictionary mappings representing the MkDocs navigation." "docstring": "Generate a list of navigation entries for mkdocs.yml.\n\nArgs:\n nav: The resolved navigation data.\n\nReturns:\n A list of dictionary mappings representing the MkDocs navigation."
} }
} }
}, },
"mkdocs_cmd": { "generate_sources": {
"name": "mkdocs_cmd", "name": "generate_sources",
"kind": "function", "kind": "function",
"path": "docforge.cli.mkdocs.mkdocs_cmd", "path": "docforge.cli.mkdocs_utils.generate_sources",
"signature": "<bound method Function.signature of Function('mkdocs_cmd', 42, 116)>", "signature": "<bound method Function.signature of Function('generate_sources', 9, 23)>",
"docstring": "Generate an mkdocs.yml configuration file by combining a template with\nthe navigation structure resolved from a docforge.nav.yml file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template.\n out: Path where the final mkdocs.yml will be written.\n site_name: The name of the documentation site." "docstring": "Generate Markdown source files for the specified module.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n docs_dir: Directory where the generated Markdown files will be written."
}, },
"Any": { "generate_config": {
"name": "Any", "name": "generate_config",
"kind": "alias", "kind": "function",
"path": "docforge.cli.mkdocs.Any", "path": "docforge.cli.mkdocs_utils.generate_config",
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>", "signature": "<bound method Function.signature of Function('generate_config', 25, 59)>",
"docstring": null "docstring": "Generate an mkdocs.yml configuration file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template (overrides built-in).\n out: Path where the final mkdocs.yml will be written.\n site_name: The display name for the documentation site."
}, },
"Dict": { "build": {
"name": "Dict", "name": "build",
"kind": "alias", "kind": "function",
"path": "docforge.cli.mkdocs.Dict", "path": "docforge.cli.mkdocs_utils.build",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>", "signature": "<bound method Function.signature of Function('build', 61, 74)>",
"docstring": null "docstring": "Build the documentation site using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
}, },
"Optional": { "serve": {
"name": "Optional", "name": "serve",
"kind": "alias", "kind": "function",
"path": "docforge.cli.mkdocs.Optional", "path": "docforge.cli.mkdocs_utils.serve",
"signature": "<bound method Alias.signature of Alias('Optional', 'typing.Optional')>", "signature": "<bound method Function.signature of Function('serve', 76, 87)>",
"docstring": null "docstring": "Serve the documentation site with live-reload using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
} }
} }
} }

View File

@@ -2,174 +2,21 @@
"module": "docforge.cli.main", "module": "docforge.cli.main",
"content": { "content": {
"path": "docforge.cli.main", "path": "docforge.cli.main",
"docstring": "Main entry point for the doc-forge CLI. This module defines the core command\ngroup and the 'tree', 'generate', 'build', and 'serve' commands.", "docstring": "Main entry point for the doc-forge CLI. This module delegates all command\nexecution to docforge.cli.commands.",
"objects": { "objects": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.main.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"Sequence": {
"name": "Sequence",
"kind": "alias",
"path": "docforge.cli.main.Sequence",
"signature": "<bound method Alias.signature of Alias('Sequence', 'typing.Sequence')>",
"docstring": null
},
"Optional": {
"name": "Optional",
"kind": "alias",
"path": "docforge.cli.main.Optional",
"signature": "<bound method Alias.signature of Alias('Optional', 'typing.Optional')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.main.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.main.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.main.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.main.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.main.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.loaders.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MkDocsRenderer": {
"name": "MkDocsRenderer",
"kind": "class",
"path": "docforge.cli.main.MkDocsRenderer",
"signature": "<bound method Alias.signature of Alias('MkDocsRenderer', 'docforge.renderers.MkDocsRenderer')>",
"docstring": "Renderer that generates Markdown source files formatted for the MkDocs\n'mkdocstrings' plugin.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.main.MkDocsRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.main.MkDocsRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.generate_sources')>",
"docstring": "Produce a set of Markdown files in the output directory based on the\nprovided Project models.\n\nArgs:\n project: The project models to render.\n out_dir: Target directory for documentation files."
}
}
},
"MCPRenderer": {
"name": "MCPRenderer",
"kind": "class",
"path": "docforge.cli.main.MCPRenderer",
"signature": "<bound method Alias.signature of Alias('MCPRenderer', 'docforge.renderers.MCPRenderer')>",
"docstring": "Renderer that emits MCP-native JSON resources from docforge models.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.main.MCPRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mcp_renderer.MCPRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.main.MCPRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mcp_renderer.MCPRenderer.generate_sources')>",
"docstring": "Generate MCP-compatible JSON resources and navigation for the project."
}
}
},
"mkdocs_cmd": {
"name": "mkdocs_cmd",
"kind": "function",
"path": "docforge.cli.main.mkdocs_cmd",
"signature": "<bound method Alias.signature of Alias('mkdocs_cmd', 'docforge.cli.mkdocs.mkdocs_cmd')>",
"docstring": "Generate an mkdocs.yml configuration file by combining a template with\nthe navigation structure resolved from a docforge.nav.yml file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template.\n out: Path where the final mkdocs.yml will be written.\n site_name: The name of the documentation site."
},
"cli": { "cli": {
"name": "cli", "name": "cli",
"kind": "function", "kind": "attribute",
"path": "docforge.cli.main.cli", "path": "docforge.cli.main.cli",
"signature": "<bound method Function.signature of Function('cli', 16, 22)>", "signature": "<bound method Alias.signature of Alias('cli', 'docforge.cli.commands.cli')>",
"docstring": "doc-forge CLI: A tool for introspecting Python projects and generating\ndocumentation." "docstring": null
},
"tree": {
"name": "tree",
"kind": "function",
"path": "docforge.cli.main.tree",
"signature": "<bound method Function.signature of Function('tree', 31, 62)>",
"docstring": "Visualize the project structure including modules and their members.\n\nArgs:\n modules: List of module paths to introspect.\n project_name: Optional project name override."
},
"generate": {
"name": "generate",
"kind": "function",
"path": "docforge.cli.main.generate",
"signature": "<bound method Function.signature of Function('generate', 78, 118)>",
"docstring": "Generate Markdown source files for the specified module.\n\nArgs:\n module: The primary module path to document.\n project_name: Optional project name override.\n docs_dir: Directory where documentation sources will be written."
},
"generate_mcp": {
"name": "generate_mcp",
"kind": "function",
"path": "docforge.cli.main.generate_mcp",
"signature": "<bound method Function.signature of Function('generate_mcp', 125, 164)>",
"docstring": "Generate MCP-compatible documentation resources for the specified module.\n\nArgs:\n module: The primary module path to document.\n project_name: Optional project name override.\n out_dir: Directory where MCP resources will be written."
},
"build": {
"name": "build",
"kind": "function",
"path": "docforge.cli.main.build",
"signature": "<bound method Function.signature of Function('build', 171, 192)>",
"docstring": "Build the documentation site using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
},
"serve_mcp": {
"name": "serve_mcp",
"kind": "function",
"path": "docforge.cli.main.serve_mcp",
"signature": "<bound method Function.signature of Function('serve_mcp', 199, 226)>",
"docstring": "Serve MCP documentation from the local mcp_docs directory."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.main.serve",
"signature": "<bound method Function.signature of Function('serve', 233, 256)>",
"docstring": "Serve the documentation site with live-reload using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
}, },
"main": { "main": {
"name": "main", "name": "main",
"kind": "function", "kind": "function",
"path": "docforge.cli.main.main", "path": "docforge.cli.main.main",
"signature": "<bound method Function.signature of Function('main', 263, 267)>", "signature": "<bound method Function.signature of Function('main', 7, 11)>",
"docstring": "CLI Entry point." "docstring": "CLI Entry point. Boots the click application."
} }
} }
} }

View File

@@ -0,0 +1,120 @@
{
"module": "docforge.cli.mcp_utils",
"content": {
"path": "docforge.cli.mcp_utils",
"docstring": null,
"objects": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.mcp_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.mcp_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.mcp_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.mcp_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.mcp_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.mcp_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.loaders.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MCPRenderer": {
"name": "MCPRenderer",
"kind": "class",
"path": "docforge.cli.mcp_utils.MCPRenderer",
"signature": "<bound method Alias.signature of Alias('MCPRenderer', 'docforge.renderers.MCPRenderer')>",
"docstring": "Renderer that emits MCP-native JSON resources from docforge models.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.mcp_utils.MCPRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mcp_renderer.MCPRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.mcp_utils.MCPRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mcp_renderer.MCPRenderer.generate_sources')>",
"docstring": "Generate MCP-compatible JSON resources and navigation for the project.\n\nArgs:\n project: The project model to render.\n out_dir: Target directory for the generated JSON files."
}
}
},
"MCPServer": {
"name": "MCPServer",
"kind": "class",
"path": "docforge.cli.mcp_utils.MCPServer",
"signature": "<bound method Alias.signature of Alias('MCPServer', 'docforge.servers.MCPServer')>",
"docstring": "MCP server for serving a pre-built MCP documentation bundle.",
"members": {
"mcp_root": {
"name": "mcp_root",
"kind": "attribute",
"path": "docforge.cli.mcp_utils.MCPServer.mcp_root",
"signature": "<bound method Alias.signature of Alias('mcp_root', 'docforge.servers.mcp_server.MCPServer.mcp_root')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "docforge.cli.mcp_utils.MCPServer.app",
"signature": "<bound method Alias.signature of Alias('app', 'docforge.servers.mcp_server.MCPServer.app')>",
"docstring": null
},
"run": {
"name": "run",
"kind": "function",
"path": "docforge.cli.mcp_utils.MCPServer.run",
"signature": "<bound method Alias.signature of Alias('run', 'docforge.servers.mcp_server.MCPServer.run')>",
"docstring": "Start the MCP server.\n\nArgs:\n transport: MCP transport (default: streamable-http)"
}
}
},
"generate_resources": {
"name": "generate_resources",
"kind": "function",
"path": "docforge.cli.mcp_utils.generate_resources",
"signature": "<bound method Function.signature of Function('generate_resources', 7, 21)>",
"docstring": "Generate MCP-compatible documentation resources.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n out_dir: Directory where the MCP JSON resources and nav will be written."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.mcp_utils.serve",
"signature": "<bound method Function.signature of Function('serve', 23, 47)>",
"docstring": "Serve MCP documentation from a pre-built bundle.\n\nArgs:\n mcp_root: Path to the directory containing index.json, nav.json, and modules/."
}
}
}
}

View File

@@ -1,95 +0,0 @@
{
"module": "docforge.cli.mkdocs",
"content": {
"path": "docforge.cli.mkdocs",
"docstring": "This module contains the 'mkdocs' CLI command, which orchestrates the generation\nof the main mkdocs.yml configuration file.",
"objects": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.mkdocs.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"resources": {
"name": "resources",
"kind": "alias",
"path": "docforge.cli.mkdocs.resources",
"signature": "<bound method Alias.signature of Alias('resources', 'importlib.resources')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.mkdocs.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"yaml": {
"name": "yaml",
"kind": "alias",
"path": "docforge.cli.mkdocs.yaml",
"signature": "<bound method Alias.signature of Alias('yaml', 'yaml')>",
"docstring": null
},
"load_nav_spec": {
"name": "load_nav_spec",
"kind": "function",
"path": "docforge.cli.mkdocs.load_nav_spec",
"signature": "<bound method Alias.signature of Alias('load_nav_spec', 'docforge.nav.load_nav_spec')>",
"docstring": "Utility function to load a NavSpec from a file.\n\nArgs:\n path: Path to the navigation specification file.\n\nReturns:\n A loaded NavSpec instance."
},
"resolve_nav": {
"name": "resolve_nav",
"kind": "function",
"path": "docforge.cli.mkdocs.resolve_nav",
"signature": "<bound method Alias.signature of Alias('resolve_nav', 'docforge.nav.resolve_nav')>",
"docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist."
},
"MkDocsNavEmitter": {
"name": "MkDocsNavEmitter",
"kind": "class",
"path": "docforge.cli.mkdocs.MkDocsNavEmitter",
"signature": "<bound method Alias.signature of Alias('MkDocsNavEmitter', 'docforge.nav.MkDocsNavEmitter')>",
"docstring": "Emitter responsible for transforming a ResolvedNav into an MkDocs-compatible\nnavigation structure.",
"members": {
"emit": {
"name": "emit",
"kind": "function",
"path": "docforge.cli.mkdocs.MkDocsNavEmitter.emit",
"signature": "<bound method Alias.signature of Alias('emit', 'docforge.nav.mkdocs.MkDocsNavEmitter.emit')>",
"docstring": "Generate a list of navigation entries for mkdocs.yml.\n\nArgs:\n nav: The resolved navigation data.\n\nReturns:\n A list of dictionary mappings representing the MkDocs navigation."
}
}
},
"mkdocs_cmd": {
"name": "mkdocs_cmd",
"kind": "function",
"path": "docforge.cli.mkdocs.mkdocs_cmd",
"signature": "<bound method Function.signature of Function('mkdocs_cmd', 42, 116)>",
"docstring": "Generate an mkdocs.yml configuration file by combining a template with\nthe navigation structure resolved from a docforge.nav.yml file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template.\n out: Path where the final mkdocs.yml will be written.\n site_name: The name of the documentation site."
},
"Any": {
"name": "Any",
"kind": "alias",
"path": "docforge.cli.mkdocs.Any",
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
"docstring": null
},
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "docforge.cli.mkdocs.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"Optional": {
"name": "Optional",
"kind": "alias",
"path": "docforge.cli.mkdocs.Optional",
"signature": "<bound method Alias.signature of Alias('Optional', 'typing.Optional')>",
"docstring": null
}
}
}
}

View File

@@ -0,0 +1,148 @@
{
"module": "docforge.cli.mkdocs_utils",
"content": {
"path": "docforge.cli.mkdocs_utils",
"docstring": null,
"objects": {
"Path": {
"name": "Path",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"resources": {
"name": "resources",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.resources",
"signature": "<bound method Alias.signature of Alias('resources', 'importlib.resources')>",
"docstring": null
},
"click": {
"name": "click",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.click",
"signature": "<bound method Alias.signature of Alias('click', 'click')>",
"docstring": null
},
"yaml": {
"name": "yaml",
"kind": "alias",
"path": "docforge.cli.mkdocs_utils.yaml",
"signature": "<bound method Alias.signature of Alias('yaml', 'yaml')>",
"docstring": null
},
"GriffeLoader": {
"name": "GriffeLoader",
"kind": "class",
"path": "docforge.cli.mkdocs_utils.GriffeLoader",
"signature": "<bound method Alias.signature of Alias('GriffeLoader', 'docforge.loaders.GriffeLoader')>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": {
"load_project": {
"name": "load_project",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.GriffeLoader.load_project",
"signature": "<bound method Alias.signature of Alias('load_project', 'docforge.loaders.griffe_loader.GriffeLoader.load_project')>",
"docstring": "Load multiple modules and combine them into a single Project models.\n\nArgs:\n module_paths: A list of dotted paths to the modules to load.\n project_name: Optional name for the project. Defaults to the first module name.\n skip_import_errors: If True, modules that fail to import will be skipped.\n\nReturns:\n A Project instance containing the loaded modules."
},
"load_module": {
"name": "load_module",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.GriffeLoader.load_module",
"signature": "<bound method Alias.signature of Alias('load_module', 'docforge.loaders.griffe_loader.GriffeLoader.load_module')>",
"docstring": "Load a single module and convert its introspection data into the docforge models.\n\nArgs:\n path: The dotted path of the module to load.\n\nReturns:\n A Module instance."
}
}
},
"discover_module_paths": {
"name": "discover_module_paths",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.discover_module_paths",
"signature": "<bound method Alias.signature of Alias('discover_module_paths', 'docforge.loaders.discover_module_paths')>",
"docstring": "Discover all Python modules under a package via filesystem traversal.\n\nRules:\n- Directory with __init__.py is treated as a package.\n- Any .py file is treated as a module.\n- All paths are converted to dotted module paths.\n\nArgs:\n module_name: The name of the package to discover.\n project_root: The root directory of the project. Defaults to current working directory.\n\nReturns:\n A sorted list of dotted module paths."
},
"MkDocsRenderer": {
"name": "MkDocsRenderer",
"kind": "class",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer",
"signature": "<bound method Alias.signature of Alias('MkDocsRenderer', 'docforge.renderers.MkDocsRenderer')>",
"docstring": "Renderer that generates Markdown source files formatted for the MkDocs\n'mkdocstrings' plugin.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer.name",
"signature": "<bound method Alias.signature of Alias('name', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.name')>",
"docstring": null
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.MkDocsRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mkdocs_renderer.MkDocsRenderer.generate_sources')>",
"docstring": "Produce a set of Markdown files in the output directory based on the\nprovided Project models.\n\nArgs:\n project: The project models to render.\n out_dir: Target directory for documentation files."
}
}
},
"load_nav_spec": {
"name": "load_nav_spec",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.load_nav_spec",
"signature": "<bound method Alias.signature of Alias('load_nav_spec', 'docforge.nav.load_nav_spec')>",
"docstring": "Utility function to load a NavSpec from a file.\n\nArgs:\n path: Path to the navigation specification file.\n\nReturns:\n A loaded NavSpec instance."
},
"resolve_nav": {
"name": "resolve_nav",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.resolve_nav",
"signature": "<bound method Alias.signature of Alias('resolve_nav', 'docforge.nav.resolve_nav')>",
"docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist."
},
"MkDocsNavEmitter": {
"name": "MkDocsNavEmitter",
"kind": "class",
"path": "docforge.cli.mkdocs_utils.MkDocsNavEmitter",
"signature": "<bound method Alias.signature of Alias('MkDocsNavEmitter', 'docforge.nav.MkDocsNavEmitter')>",
"docstring": "Emitter responsible for transforming a ResolvedNav into an MkDocs-compatible\nnavigation structure.",
"members": {
"emit": {
"name": "emit",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.MkDocsNavEmitter.emit",
"signature": "<bound method Alias.signature of Alias('emit', 'docforge.nav.mkdocs.MkDocsNavEmitter.emit')>",
"docstring": "Generate a list of navigation entries for mkdocs.yml.\n\nArgs:\n nav: The resolved navigation data.\n\nReturns:\n A list of dictionary mappings representing the MkDocs navigation."
}
}
},
"generate_sources": {
"name": "generate_sources",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.generate_sources",
"signature": "<bound method Function.signature of Function('generate_sources', 9, 23)>",
"docstring": "Generate Markdown source files for the specified module.\n\nArgs:\n module: The dotted path of the primary module to document.\n project_name: Optional override for the project name.\n docs_dir: Directory where the generated Markdown files will be written."
},
"generate_config": {
"name": "generate_config",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.generate_config",
"signature": "<bound method Function.signature of Function('generate_config', 25, 59)>",
"docstring": "Generate an mkdocs.yml configuration file.\n\nArgs:\n docs_dir: Path to the directory containing documentation Markdown files.\n nav_file: Path to the docforge.nav.yml specification.\n template: Optional path to an mkdocs.yml template (overrides built-in).\n out: Path where the final mkdocs.yml will be written.\n site_name: The display name for the documentation site."
},
"build": {
"name": "build",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.build",
"signature": "<bound method Function.signature of Function('build', 61, 74)>",
"docstring": "Build the documentation site using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
},
"serve": {
"name": "serve",
"kind": "function",
"path": "docforge.cli.mkdocs_utils.serve",
"signature": "<bound method Function.signature of Function('serve', 76, 87)>",
"docstring": "Serve the documentation site with live-reload using MkDocs.\n\nArgs:\n mkdocs_yml: Path to the mkdocs.yml configuration file."
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -252,7 +252,7 @@
"name": "GriffeLoader", "name": "GriffeLoader",
"kind": "class", "kind": "class",
"path": "docforge.loaders.griffe_loader.GriffeLoader", "path": "docforge.loaders.griffe_loader.GriffeLoader",
"signature": "<bound method Class.signature of Class('GriffeLoader', 65, 188)>", "signature": "<bound method Class.signature of Class('GriffeLoader', 65, 224)>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.", "docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": { "members": {
"load_project": { "load_project": {

View File

@@ -289,7 +289,7 @@
"name": "GriffeLoader", "name": "GriffeLoader",
"kind": "class", "kind": "class",
"path": "docforge.loaders.griffe_loader.GriffeLoader", "path": "docforge.loaders.griffe_loader.GriffeLoader",
"signature": "<bound method Class.signature of Class('GriffeLoader', 65, 188)>", "signature": "<bound method Class.signature of Class('GriffeLoader', 65, 224)>",
"docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.", "docstring": "Loads Python modules and extracts documentation using the Griffe introspection engine.",
"members": { "members": {
"load_project": { "load_project": {

View File

@@ -297,7 +297,7 @@
"name": "resolve_nav", "name": "resolve_nav",
"kind": "function", "kind": "function",
"path": "docforge.nav.resolver.resolve_nav", "path": "docforge.nav.resolver.resolve_nav",
"signature": "<bound method Function.signature of Function('resolve_nav', 59, 112)>", "signature": "<bound method Function.signature of Function('resolve_nav', 59, 124)>",
"docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist." "docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist."
}, },
"Optional": { "Optional": {

View File

@@ -110,7 +110,7 @@
"name": "resolve_nav", "name": "resolve_nav",
"kind": "function", "kind": "function",
"path": "docforge.nav.resolver.resolve_nav", "path": "docforge.nav.resolver.resolve_nav",
"signature": "<bound method Function.signature of Function('resolve_nav', 59, 112)>", "signature": "<bound method Function.signature of Function('resolve_nav', 59, 124)>",
"docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist." "docstring": "Create a ResolvedNav by processing a NavSpec against the filesystem.\nThis expands globs and validates the existence of referenced files.\n\nArgs:\n spec: The navigation specification to resolve.\n docs_root: The root directory for documentation files.\n\nReturns:\n A ResolvedNav instance.\n\nRaises:\n FileNotFoundError: If a pattern doesn't match any files or the docs_root doesn't exist."
}, },
"Optional": { "Optional": {

View File

@@ -46,7 +46,7 @@
"kind": "function", "kind": "function",
"path": "docforge.renderers.MCPRenderer.generate_sources", "path": "docforge.renderers.MCPRenderer.generate_sources",
"signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mcp_renderer.MCPRenderer.generate_sources')>", "signature": "<bound method Alias.signature of Alias('generate_sources', 'docforge.renderers.mcp_renderer.MCPRenderer.generate_sources')>",
"docstring": "Generate MCP-compatible JSON resources and navigation for the project." "docstring": "Generate MCP-compatible JSON resources and navigation for the project.\n\nArgs:\n project: The project model to render.\n out_dir: Target directory for the generated JSON files."
} }
} }
}, },
@@ -383,7 +383,7 @@
"name": "MCPRenderer", "name": "MCPRenderer",
"kind": "class", "kind": "class",
"path": "docforge.renderers.mcp_renderer.MCPRenderer", "path": "docforge.renderers.mcp_renderer.MCPRenderer",
"signature": "<bound method Class.signature of Class('MCPRenderer', 8, 102)>", "signature": "<bound method Class.signature of Class('MCPRenderer', 8, 122)>",
"docstring": "Renderer that emits MCP-native JSON resources from docforge models.", "docstring": "Renderer that emits MCP-native JSON resources from docforge models.",
"members": { "members": {
"name": { "name": {
@@ -397,8 +397,8 @@
"name": "generate_sources", "name": "generate_sources",
"kind": "function", "kind": "function",
"path": "docforge.renderers.mcp_renderer.MCPRenderer.generate_sources", "path": "docforge.renderers.mcp_renderer.MCPRenderer.generate_sources",
"signature": "<bound method Function.signature of Function('generate_sources', 15, 49)>", "signature": "<bound method Function.signature of Function('generate_sources', 15, 53)>",
"docstring": "Generate MCP-compatible JSON resources and navigation for the project." "docstring": "Generate MCP-compatible JSON resources and navigation for the project.\n\nArgs:\n project: The project model to render.\n out_dir: Target directory for the generated JSON files."
} }
} }
} }

View File

@@ -210,7 +210,7 @@
"name": "MCPRenderer", "name": "MCPRenderer",
"kind": "class", "kind": "class",
"path": "docforge.renderers.mcp_renderer.MCPRenderer", "path": "docforge.renderers.mcp_renderer.MCPRenderer",
"signature": "<bound method Class.signature of Class('MCPRenderer', 8, 102)>", "signature": "<bound method Class.signature of Class('MCPRenderer', 8, 122)>",
"docstring": "Renderer that emits MCP-native JSON resources from docforge models.", "docstring": "Renderer that emits MCP-native JSON resources from docforge models.",
"members": { "members": {
"name": { "name": {
@@ -224,8 +224,8 @@
"name": "generate_sources", "name": "generate_sources",
"kind": "function", "kind": "function",
"path": "docforge.renderers.mcp_renderer.MCPRenderer.generate_sources", "path": "docforge.renderers.mcp_renderer.MCPRenderer.generate_sources",
"signature": "<bound method Function.signature of Function('generate_sources', 15, 49)>", "signature": "<bound method Function.signature of Function('generate_sources', 15, 53)>",
"docstring": "Generate MCP-compatible JSON resources and navigation for the project." "docstring": "Generate MCP-compatible JSON resources and navigation for the project.\n\nArgs:\n project: The project model to render.\n out_dir: Target directory for the generated JSON files."
} }
} }
} }

View File

@@ -87,7 +87,7 @@
"name": "MCPServer", "name": "MCPServer",
"kind": "class", "kind": "class",
"path": "docforge.servers.mcp_server.MCPServer", "path": "docforge.servers.mcp_server.MCPServer",
"signature": "<bound method Class.signature of Class('MCPServer', 10, 73)>", "signature": "<bound method Class.signature of Class('MCPServer', 10, 95)>",
"docstring": "MCP server for serving a pre-built MCP documentation bundle.", "docstring": "MCP server for serving a pre-built MCP documentation bundle.",
"members": { "members": {
"mcp_root": { "mcp_root": {
@@ -108,7 +108,7 @@
"name": "run", "name": "run",
"kind": "function", "kind": "function",
"path": "docforge.servers.mcp_server.MCPServer.run", "path": "docforge.servers.mcp_server.MCPServer.run",
"signature": "<bound method Function.signature of Function('run', 66, 73)>", "signature": "<bound method Function.signature of Function('run', 88, 95)>",
"docstring": "Start the MCP server.\n\nArgs:\n transport: MCP transport (default: streamable-http)" "docstring": "Start the MCP server.\n\nArgs:\n transport: MCP transport (default: streamable-http)"
} }
} }

View File

@@ -50,7 +50,7 @@
"name": "MCPServer", "name": "MCPServer",
"kind": "class", "kind": "class",
"path": "docforge.servers.mcp_server.MCPServer", "path": "docforge.servers.mcp_server.MCPServer",
"signature": "<bound method Class.signature of Class('MCPServer', 10, 73)>", "signature": "<bound method Class.signature of Class('MCPServer', 10, 95)>",
"docstring": "MCP server for serving a pre-built MCP documentation bundle.", "docstring": "MCP server for serving a pre-built MCP documentation bundle.",
"members": { "members": {
"mcp_root": { "mcp_root": {
@@ -71,7 +71,7 @@
"name": "run", "name": "run",
"kind": "function", "kind": "function",
"path": "docforge.servers.mcp_server.MCPServer.run", "path": "docforge.servers.mcp_server.MCPServer.run",
"signature": "<bound method Function.signature of Function('run', 66, 73)>", "signature": "<bound method Function.signature of Function('run', 88, 95)>",
"docstring": "Start the MCP server.\n\nArgs:\n transport: MCP transport (default: streamable-http)" "docstring": "Start the MCP server.\n\nArgs:\n transport: MCP transport (default: streamable-http)"
} }
} }

View File

@@ -7,13 +7,21 @@
"module": "docforge.cli", "module": "docforge.cli",
"resource": "doc://modules/docforge.cli" "resource": "doc://modules/docforge.cli"
}, },
{
"module": "docforge.cli.commands",
"resource": "doc://modules/docforge.cli.commands"
},
{ {
"module": "docforge.cli.main", "module": "docforge.cli.main",
"resource": "doc://modules/docforge.cli.main" "resource": "doc://modules/docforge.cli.main"
}, },
{ {
"module": "docforge.cli.mkdocs", "module": "docforge.cli.mcp_utils",
"resource": "doc://modules/docforge.cli.mkdocs" "resource": "doc://modules/docforge.cli.mcp_utils"
},
{
"module": "docforge.cli.mkdocs_utils",
"resource": "doc://modules/docforge.cli.mkdocs_utils"
}, },
{ {
"module": "docforge.loaders", "module": "docforge.loaders",

View File

@@ -1,4 +1,4 @@
site_name: DocForge site_name: docforge
theme: theme:
name: material name: material
@@ -57,4 +57,6 @@ nav:
- CLI: - CLI:
- docforge/cli/index.md - docforge/cli/index.md
- docforge/cli/main.md - docforge/cli/main.md
- docforge/cli/mkdocs.md - docforge/cli/commands.md
- docforge/cli/mcp_utils.md
- docforge/cli/mkdocs_utils.md

View File

@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "doc-forge" name = "doc-forge"
version = "0.0.2" version = "0.0.3"
description = "A renderer-agnostic Python documentation compiler" description = "A renderer-agnostic Python documentation compiler"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

View File

@@ -1,111 +0,0 @@
import json
import pytest
from pathlib import Path
from click.testing import CliRunner
@pytest.fixture
def cli_runner() -> CliRunner:
"""Click CLI runner."""
return CliRunner()
@pytest.fixture
def fake_mkdocs_yml(tmp_path: Path) -> Path:
"""Create a minimal mkdocs.yml file."""
yml = tmp_path / "mkdocs.yml"
yml.write_text(
"""
site_name: Test Docs
nav: []
plugins:
- mkdocstrings
""",
encoding="utf-8",
)
return yml
@pytest.fixture
def mock_mkdocs_load_config(monkeypatch):
"""Mock mkdocs.config.load_config."""
def fake_load_config(path):
return object() # dummy config object
monkeypatch.setattr(
"mkdocs.config.load_config",
fake_load_config,
)
@pytest.fixture
def mock_mkdocs_build(monkeypatch):
called = {"value": False}
def fake_build(config):
called["value"] = True
monkeypatch.setattr(
"mkdocs.commands.build.build",
fake_build,
)
return lambda: called["value"]
@pytest.fixture
def mock_mkdocs_serve(monkeypatch):
called = {"value": False}
def fake_serve(*args, **kwargs):
called["value"] = True
monkeypatch.setattr(
"mkdocs.commands.serve.serve",
fake_serve,
)
return lambda: called["value"]
@pytest.fixture
def fake_mcp_docs(tmp_path: Path) -> Path:
"""
Create a minimal valid MCP bundle in mcp_docs/.
"""
mcp_root = tmp_path / "mcp_docs"
modules_dir = mcp_root / "modules"
modules_dir.mkdir(parents=True)
(mcp_root / "index.json").write_text(
json.dumps({"project": "test", "type": "docforge-model"}),
encoding="utf-8",
)
(mcp_root / "nav.json").write_text(
json.dumps([]),
encoding="utf-8",
)
(modules_dir / "test.mod.json").write_text(
json.dumps({"module": "test.mod", "content": {}}),
encoding="utf-8",
)
return mcp_root
@pytest.fixture
def mock_mcp_server_run(monkeypatch):
"""
Mock MCPServer.run so no real server is started.
"""
called = {"value": False}
def fake_run(self, transport="streamable-http"):
called["value"] = True
monkeypatch.setattr(
"docforge.servers.MCPServer.run",
fake_run,
)
return lambda: called["value"]

View File

@@ -1,20 +0,0 @@
from docforge.cli.main import cli
def test_build_command(
cli_runner,
fake_mkdocs_yml,
mock_mkdocs_load_config,
mock_mkdocs_build,
):
result = cli_runner.invoke(
cli,
[
"build",
"--mkdocs-yml",
str(fake_mkdocs_yml),
],
)
assert result.exit_code == 0
assert mock_mkdocs_build() is True

View File

@@ -1,35 +1,29 @@
from pathlib import Path from pathlib import Path
from docforge.cli.main import cli from docforge.cli.main import cli
def test_mcp_build(cli_runner):
def test_generate_command(cli_runner):
with cli_runner.isolated_filesystem(): with cli_runner.isolated_filesystem():
cwd = Path.cwd() cwd = Path.cwd()
# Create package structure
pkg = cwd / "testpkg" pkg = cwd / "testpkg"
pkg.mkdir() pkg.mkdir()
(pkg / "__init__.py").write_text("") (pkg / "__init__.py").write_text("")
(pkg / "mod.py").write_text("def f(): ...\n") (pkg / "mod.py").write_text("def f(): ...\n")
docs_dir = cwd / "docs" out_dir = cwd / "mcp_docs"
result = cli_runner.invoke( result = cli_runner.invoke(
cli, cli,
[ [
"generate", "build",
"--mcp",
"--module", "--module",
"testpkg", "testpkg",
"--docs-dir", "--out-dir",
str(docs_dir), str(out_dir),
], ],
) )
assert result.exit_code == 0 assert result.exit_code == 0
assert (out_dir / "index.json").exists()
md = docs_dir / "testpkg" / "mod.md" assert (out_dir / "nav.json").exists()
assert md.exists() assert (out_dir / "modules" / "testpkg.mod.json").exists()
content = md.read_text()
assert "::: testpkg.mod" in content

View File

@@ -0,0 +1,99 @@
from pathlib import Path
from docforge.cli.main import cli
def test_mkdocs_build_full_flow(
cli_runner,
mock_mkdocs_build,
mock_mkdocs_load_config,
tmp_path,
):
# This test covers what used to be generate + mkdocs + build
with cli_runner.isolated_filesystem():
cwd = Path.cwd()
pkg = cwd / "testpkg"
pkg.mkdir()
(pkg / "__init__.py").write_text("")
(pkg / "mod.py").write_text("def f(): ...\n")
nav_file = cwd / "docforge.nav.yml"
nav_file.write_text("home: testpkg/index.md\ngroups: {}\n")
# We need to create a dummy testpkg/index.md for nav resolution if it's there
# But generate_sources will create it.
# Wait, the current logic runs generate_sources first, THEN generate_config.
result = cli_runner.invoke(
cli,
[
"build",
"--mkdocs",
"--module",
"testpkg",
"--site-name",
"Test Site",
"--docs-dir",
"docs",
"--mkdocs-yml",
"mkdocs.yml",
],
)
assert result.exit_code == 0
assert mock_mkdocs_build() is True
assert (cwd / "mkdocs.yml").exists()
assert (cwd / "docs" / "testpkg" / "mod.md").exists()
def test_mkdocs_build_missing_module_fails(cli_runner):
result = cli_runner.invoke(cli, ["build", "--mkdocs", "--site-name", "Test"])
assert result.exit_code != 0
assert "--module is required" in result.output
def test_mkdocs_build_without_site_name_uses_module_as_default_full_flow(
cli_runner,
mock_mkdocs_build,
mock_mkdocs_load_config,
):
# Full integration test: real generation, real config, mocked mkdocs build
with cli_runner.isolated_filesystem():
cwd = Path.cwd()
# Create a minimal Python package
pkg = cwd / "testpkg"
pkg.mkdir()
(pkg / "__init__.py").write_text("")
(pkg / "mod.py").write_text("def f(): ...\n")
# Create nav spec expected by generate_config
nav_file = cwd / "docforge.nav.yml"
nav_file.write_text(
"home: testpkg/index.md\ngroups: {}\n",
encoding="utf-8",
)
result = cli_runner.invoke(
cli,
[
"build",
"--mkdocs",
"--module",
"testpkg",
"--docs-dir",
"docs",
"--mkdocs-yml",
"mkdocs.yml",
],
)
assert result.exit_code == 0
assert mock_mkdocs_build() is True
# MkDocs config must exist
mkdocs_yml = cwd / "mkdocs.yml"
assert mkdocs_yml.exists()
# Site name must default to module name
content = mkdocs_yml.read_text()
assert "site_name: testpkg" in content
# Docs must be generated
assert (cwd / "docs" / "testpkg" / "mod.md").exists()

View File

@@ -1,123 +0,0 @@
from pathlib import Path
import yaml
from click.testing import CliRunner
from docforge.cli.main import cli
def _write_nav_spec(path: Path) -> None:
path.write_text(
"""
home: openapi_first/index.md
groups:
Core:
- openapi_first/app.md
- openapi_first/client.md
""".strip(),
encoding="utf-8",
)
def _write_docs(docs: Path) -> None:
files = [
"openapi_first/index.md",
"openapi_first/app.md",
"openapi_first/client.md",
]
for rel in files:
p = docs / rel
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(f"# {rel}", encoding="utf-8")
def test_mkdocs_uses_builtin_template(tmp_path: Path) -> None:
docs = tmp_path / "docs"
docs.mkdir()
nav_file = tmp_path / "docforge.nav.yml"
out_file = tmp_path / "mkdocs.yml"
_write_docs(docs)
_write_nav_spec(nav_file)
runner = CliRunner()
result = runner.invoke(
cli,
[
"mkdocs",
"--site-name",
"DocForge",
"--docs-dir",
str(docs),
"--nav",
str(nav_file),
"--out",
str(out_file),
],
)
assert result.exit_code == 0
assert out_file.exists()
def test_mkdocs_overrides_template(tmp_path: Path) -> None:
docs = tmp_path / "docs"
docs.mkdir()
nav_file = tmp_path / "docforge.nav.yml"
template = tmp_path / "custom.yml"
out_file = tmp_path / "mkdocs.yml"
_write_docs(docs)
_write_nav_spec(nav_file)
template.write_text(
"""
site_name: Custom Site
theme:
name: readthedocs
""".strip(),
encoding="utf-8",
)
runner = CliRunner()
result = runner.invoke(
cli,
[
"mkdocs",
"--site-name",
"Override Site",
"--docs-dir",
str(docs),
"--nav",
str(nav_file),
"--template",
str(template),
"--out",
str(out_file),
],
)
assert result.exit_code == 0
assert out_file.exists()
def test_mkdocs_missing_nav_fails(tmp_path: Path) -> None:
docs = tmp_path / "docs"
docs.mkdir()
runner = CliRunner()
result = runner.invoke(
cli,
[
"mkdocs",
"--site-name",
"DocForge",
"--docs-dir",
str(docs),
],
)
assert result.exit_code != 0
assert "Nav spec not found" in result.output

View File

@@ -1,7 +1,6 @@
from docforge.cli.main import cli from docforge.cli.main import cli
def test_mcp_serve(
def test_serve_mcp(
cli_runner, cli_runner,
fake_mcp_docs, fake_mcp_docs,
mock_mcp_server_run, mock_mcp_server_run,
@@ -11,7 +10,7 @@ def test_serve_mcp(
result = cli_runner.invoke( result = cli_runner.invoke(
cli, cli,
["serve-mcp"], ["serve", "--mcp", "--out-dir", str(fake_mcp_docs)],
) )
assert result.exit_code == 0 assert result.exit_code == 0

View File

@@ -1,7 +1,6 @@
from docforge.cli.main import cli from docforge.cli.main import cli
def test_mkdocs_serve(
def test_serve_command(
cli_runner, cli_runner,
fake_mkdocs_yml, fake_mkdocs_yml,
mock_mkdocs_serve, mock_mkdocs_serve,
@@ -10,6 +9,7 @@ def test_serve_command(
cli, cli,
[ [
"serve", "serve",
"--mkdocs",
"--mkdocs-yml", "--mkdocs-yml",
str(fake_mkdocs_yml), str(fake_mkdocs_yml),
], ],

View File

@@ -1,24 +0,0 @@
from docforge.cli.main import cli
def test_tree_command(cli_runner, temp_package):
(temp_package / "mod.py").write_text(
'''
class A:
def f(self): ...
'''
)
result = cli_runner.invoke(
cli,
[
"tree",
"--modules",
"testpkg.mod",
],
)
assert result.exit_code == 0
assert "testpkg" in result.output
assert "mod" in result.output
assert "A" in result.output

View File

@@ -1,7 +1,9 @@
import sys import sys
import json
import pytest
from pathlib import Path from pathlib import Path
import pytest from click.testing import CliRunner
@pytest.fixture @pytest.fixture
@@ -16,3 +18,109 @@ def temp_package(tmp_path: Path):
sys.path.insert(0, str(tmp_path)) sys.path.insert(0, str(tmp_path))
yield pkg yield pkg
sys.path.remove(str(tmp_path)) sys.path.remove(str(tmp_path))
@pytest.fixture
def cli_runner() -> CliRunner:
"""Click CLI runner."""
return CliRunner()
@pytest.fixture
def fake_mkdocs_yml(tmp_path: Path) -> Path:
"""Create a minimal mkdocs.yml file."""
yml = tmp_path / "mkdocs.yml"
yml.write_text(
"""
site_name: Test Docs
nav: []
plugins:
- mkdocstrings
""",
encoding="utf-8",
)
return yml
@pytest.fixture
def mock_mkdocs_load_config(monkeypatch):
"""Mock mkdocs.config.load_config."""
def fake_load_config(path):
return object() # dummy config object
monkeypatch.setattr(
"mkdocs.config.load_config",
fake_load_config,
)
@pytest.fixture
def mock_mkdocs_build(monkeypatch):
called = {"value": False}
def fake_build(config):
called["value"] = True
monkeypatch.setattr(
"mkdocs.commands.build.build",
fake_build,
)
return lambda: called["value"]
@pytest.fixture
def mock_mkdocs_serve(monkeypatch):
called = {"value": False}
def fake_serve(*args, **kwargs):
called["value"] = True
monkeypatch.setattr(
"mkdocs.commands.serve.serve",
fake_serve,
)
return lambda: called["value"]
@pytest.fixture
def fake_mcp_docs(tmp_path: Path) -> Path:
"""
Create a minimal valid MCP bundle in mcp_docs/.
"""
mcp_root = tmp_path / "mcp_docs"
modules_dir = mcp_root / "modules"
modules_dir.mkdir(parents=True)
(mcp_root / "index.json").write_text(
json.dumps({"project": "test", "type": "docforge-model"}),
encoding="utf-8",
)
(mcp_root / "nav.json").write_text(
json.dumps([]),
encoding="utf-8",
)
(modules_dir / "test.mod.json").write_text(
json.dumps({"module": "test.mod", "content": {}}),
encoding="utf-8",
)
return mcp_root
@pytest.fixture
def mock_mcp_server_run(monkeypatch):
"""
Mock MCPServer.run so no real server is started.
"""
called = {"value": False}
def fake_run(self, transport="streamable-http"):
called["value"] = True
monkeypatch.setattr(
"docforge.servers.MCPServer.run",
fake_run,
)
return lambda: called["value"]