updated docs strings and added README.md

This commit is contained in:
2026-03-08 17:59:55 +05:30
parent e8e16f3996
commit 8253c25928
37 changed files with 1091 additions and 834 deletions

View File

@@ -1,4 +1,6 @@
"""
# Summary
Renderer-agnostic Python documentation compiler that converts Python docstrings
into structured documentation for both humans (MkDocs) and machines (MCP / AI agents).
@@ -101,13 +103,13 @@ This architecture ensures deterministic documentation generation.
Typical flow:
Python package
|
Loader (static analysis)
|
Semantic model
|
Renderer
|
MkDocs site or MCP JSON
---
@@ -117,7 +119,7 @@ Typical flow:
GSDFC defines how docstrings must be written so they render correctly in MkDocs and remain machine-parsable by doc-forge and AI tooling.
- Docstrings are the single source of truth.
- doc-forge compiles docstrings but does not generate documentation content.
- `doc-forge` compiles docstrings but does not generate documentation content.
- Documentation follows the Python import hierarchy.
- Every public symbol should have a complete and accurate docstring.
@@ -129,34 +131,33 @@ GSDFC defines how docstrings must be written so they render correctly in MkDocs
- Use **Google-style structured sections** at class, function, and method level.
- Use type hints in signatures instead of duplicating types in prose.
- Write summaries in imperative form.
- Sections are separated by ```---```
- Sections are separated by `---`
---
## Notes subsection grouping
# Notes subsection grouping
- Group related information using labeled subsections.
Group related information using labeled subsections.
Example:
Notes Example:
Notes:
**Guarantees:**
Notes:
**Guarantees:**
- deterministic behavior
- deterministic behavior
**Lifecycle:**
**Lifecycle:**
- created during initialization
- reused across executions
- created during initialization
- reused across executions
**Thread safety:**
**Thread safety:**
- safe for concurrent reads
- safe for concurrent reads
---
## Example formatting
# Example formatting
- Use indentation for examples.
- Indent section contents using four spaces.
@@ -192,9 +193,10 @@ Avoid fenced code blocks inside structured sections.
---
## Separator rules
# Separator rules
Use horizontal separators only at docstring root level to separate sections:
```markdown
---
```
@@ -209,9 +211,9 @@ Do not use separators inside code sections.
---
## Package docstrings
# Package docstrings
- Package docstrings act as the documentation home page.
Package docstrings act as the documentation home page.
Recommended sections:
@@ -229,6 +231,8 @@ Example:
Package Doc String:
'''
# Summary
Foo-bar processing framework.
Provides tools for defining Foo objects and executing Bar pipelines.
@@ -259,9 +263,9 @@ Example:
---
## Module docstrings
# Module docstrings
- Module docstrings describe a subsystem.
Module docstrings describe a subsystem.
Recommended sections:
@@ -273,6 +277,8 @@ Example:
Module Doc String:
'''
# Summary
Foo execution subsystem.
Provides utilities for executing Foo objects through Bar stages.
@@ -296,9 +302,9 @@ Example:
---
## Class docstrings
# Class docstrings
- Class docstrings define object responsibility, lifecycle, and attributes.
Class docstrings define object responsibility, lifecycle, and attributes.
Recommended sections:
@@ -373,9 +379,9 @@ Example:
---
## Function and method docstrings
# Function and method docstrings
- Function docstrings define API contracts.
Function docstrings define API contracts.
Recommended sections:
@@ -465,9 +471,9 @@ Example:
---
## Property docstrings
# Property docstrings
- Properties must document return values.
Properties must document return values.
Example:
Property Doc String:
@@ -493,9 +499,9 @@ Example:
---
## Attribute documentation
# Attribute documentation
- Document attributes in class docstrings using Attributes:.
Document attributes in class docstrings using `Attributes:`.
Example:
Attribute Doc String:
@@ -515,7 +521,7 @@ Example:
---
## Parsing guarantees
# Parsing guarantees
GSDFC ensures doc-forge can deterministically extract:

View File

@@ -1,9 +1,11 @@
"""
# Summary
Command line interface entry point for doc-forge.
This module exposes the primary CLI entry function used by the
``doc-forge`` command. The actual command implementation resides in
``docforge.cli.main``, while this module provides a stable import path
`doc-forge` command. The actual command implementation resides in
`docforge.cli.main`, while this module provides a stable import path
for external tools and the package entry point configuration.
The CLI is responsible for orchestrating documentation workflows such as
@@ -13,17 +15,22 @@ servers.
---
Typical usage
-------------
# Typical usage
The CLI is normally invoked through the installed command:
doc-forge <command> [options]
```bash
doc-forge <command> [options]
```
Programmatic invocation is also possible:
Example:
```python
from docforge.cli import main
main()
```
---
"""

View File

@@ -1,3 +1,11 @@
"""
# Summary
Command definitions for the doc-forge CLI.
Provides the CLI structure using Click, including build, serve, and tree commands.
"""
import click
from pathlib import Path
from typing import Sequence, Optional
@@ -58,22 +66,42 @@ def build(
- MCP structured documentation resources
Args:
mcp: Enable MCP documentation generation.
mkdocs: Enable MkDocs documentation generation.
module_is_source: Treat the specified module directory as the
project root.
module: Python module import path to document.
project_name: Optional override for the project name.
site_name: Display name for the MkDocs site.
docs_dir: Directory where Markdown documentation sources
will be generated.
nav_file: Path to the navigation specification file.
template: Optional custom MkDocs configuration template.
mkdocs_yml: Output path for the generated MkDocs configuration.
out_dir: Output directory for generated MCP resources.
mcp (bool):
Enable MCP documentation generation.
mkdocs (bool):
Enable MkDocs documentation generation.
module_is_source (bool):
Treat the specified module directory as the project root.
module (Optional[str]):
Python module import path to document.
project_name (Optional[str]):
Optional override for the project name.
site_name (Optional[str]):
Display name for the MkDocs site.
docs_dir (Path):
Directory where Markdown documentation sources will be generated.
nav_file (Path):
Path to the navigation specification file.
template (Optional[Path]):
Optional custom MkDocs configuration template.
mkdocs_yml (Path):
Output path for the generated MkDocs configuration.
out_dir (Path):
Output directory for generated MCP resources.
Raises:
click.UsageError: If required options are missing or conflicting.
click.UsageError:
If required options are missing or conflicting.
"""
if not mcp and not mkdocs:
raise click.UsageError("Must specify either --mcp or --mkdocs")
@@ -130,14 +158,24 @@ def serve(
- An MCP server exposing structured documentation resources
Args:
mcp: Serve documentation using the MCP server.
mkdocs: Serve the MkDocs development site.
module: Python module import path to serve via MCP.
mkdocs_yml: Path to the MkDocs configuration file.
out_dir: Root directory containing MCP documentation resources.
mcp (bool):
Serve documentation using the MCP server.
mkdocs (bool):
Serve the MkDocs development site.
module (Optional[str]):
Python module import path to serve via MCP.
mkdocs_yml (Path):
Path to the MkDocs configuration file.
out_dir (Path):
Root directory containing MCP documentation resources.
Raises:
click.UsageError: If invalid or conflicting options are provided.
click.UsageError:
If invalid or conflicting options are provided.
"""
if mcp and mkdocs:
raise click.UsageError("Cannot specify both --mcp and --mkdocs")
@@ -174,8 +212,11 @@ def tree(
objects, including modules, classes, functions, and members.
Args:
module: Python module import path to introspect.
project_name: Optional name to display as the project root.
module (str):
Python module import path to introspect.
project_name (Optional[str]):
Optional name to display as the project root.
"""
loader = GriffeLoader()
project = loader.load_project([module], project_name)
@@ -196,8 +237,11 @@ def _print_object(obj, indent: str) -> None:
and prints each object with indentation to represent hierarchy.
Args:
obj: Documentation object to print.
indent: Current indentation prefix used for nested members.
obj:
Documentation object to print.
indent (str):
Current indentation prefix used for nested members.
"""
click.echo(f"{indent}├── {obj.name}")
for member in obj.get_all_members():

View File

@@ -1,8 +1,10 @@
"""
# Summary
Command-line entry point for the doc-forge CLI.
This module exposes the executable entry point that initializes the
Click command group defined in ``docforge.cli.commands``.
Click command group defined in `docforge.cli.commands`.
"""
from docforge.cli.commands import cli
@@ -13,7 +15,7 @@ def main() -> None:
Run the doc-forge command-line interface.
This function initializes and executes the Click CLI application.
It is used as the console entry point when invoking ``doc-forge``
It is used as the console entry point when invoking `doc-forge`
from the command line.
"""
cli()

View File

@@ -1,3 +1,9 @@
"""
# Summary
Utilities for working with MCP in the doc-forge CLI.
"""
from pathlib import Path
import click
from docforge.loaders import GriffeLoader, discover_module_paths
@@ -14,12 +20,17 @@ def generate_resources(module: str, project_name: str | None, out_dir: Path) ->
to the specified output directory.
Args:
module: Python module import path used as the entry point for
module (str):
Python module import path used as the entry point for
documentation generation.
project_name: Optional override for the project name used in
generated documentation metadata.
out_dir: Directory where MCP resources (index.json, nav.json,
and module data) will be written.
project_name (Optional[str]):
Optional override for the project name used in generated
documentation metadata.
out_dir (Path):
Directory where MCP resources (index.json, nav.json, and module data)
will be written.
"""
loader = GriffeLoader()
discovered_paths = discover_module_paths(module)
@@ -37,14 +48,17 @@ def serve(module: str, mcp_root: Path) -> None:
navigation structure, and module documentation through MCP endpoints.
Args:
module: Python module import path used to identify the served
module (str):
Python module import path used to identify the served
documentation instance.
mcp_root: Path to the directory containing the MCP documentation
mcp_root (Path):
Path to the directory containing the MCP documentation
bundle (index.json, nav.json, and modules/).
Raises:
click.ClickException: If the MCP documentation bundle is missing
required files or directories.
click.ClickException:
If the MCP documentation bundle is missing required files or directories.
"""
if not mcp_root.exists():
raise click.ClickException(f"mcp_docs directory not found: {mcp_root}")

View File

@@ -1,3 +1,9 @@
"""
# Summary
Utilities for working with MkDocs in the doc-forge CLI.
"""
from pathlib import Path
from importlib import resources
import click
@@ -21,13 +27,19 @@ def generate_sources(
use with MkDocs.
Args:
module: Python module import path used as the entry point for
module (str):
Python module import path used as the entry point for
documentation generation.
docs_dir: Directory where the generated Markdown files will be written.
project_name: Optional override for the project name used in
documentation metadata.
module_is_source: If True, treat the specified module directory as
the project root rather than a nested module.
docs_dir (Path):
Directory where the generated Markdown files will be written.
project_name (Optional[str]):
Optional override for the project name used in documentation metadata.
module_is_source (Optional[bool]):
If True, treat the specified module directory as the project root
rather than a nested module.
"""
loader = GriffeLoader()
discovered_paths = discover_module_paths(module)
@@ -55,24 +67,32 @@ def generate_config(
site_name: str,
) -> None:
"""
Generate an ``mkdocs.yml`` configuration file.
Generate an `mkdocs.yml` configuration file.
The configuration is created by combining a template configuration
with a navigation structure derived from the docforge navigation
specification.
Args:
docs_dir: Directory containing generated documentation Markdown files.
nav_file: Path to the ``docforge.nav.yml`` navigation specification.
template: Optional path to a custom MkDocs configuration template.
If not provided, a built-in template will be used.
out: Destination path where the generated ``mkdocs.yml`` file
will be written.
site_name: Display name for the generated documentation site.
docs_dir (Path):
Directory containing generated documentation Markdown files.
nav_file (Path):
Path to the `docforge.nav.yml` navigation specification.
template (Optional[Path]):
Optional path to a custom MkDocs configuration template. If not
provided, a built-in template will be used.
out (Path):
Destination path where the generated `mkdocs.yml` file will be written.
site_name (str):
Display name for the generated documentation site.
Raises:
click.FileError: If the navigation specification or template
file cannot be found.
click.FileError:
If the navigation specification or template file cannot be found.
"""
if not nav_file.exists():
raise click.FileError(str(nav_file), hint="Nav spec not found")
@@ -108,10 +128,12 @@ def build(mkdocs_yml: Path) -> None:
build command to generate the final static documentation site.
Args:
mkdocs_yml: Path to the ``mkdocs.yml`` configuration file.
mkdocs_yml (Path):
Path to the `mkdocs.yml` configuration file.
Raises:
click.ClickException: If the configuration file does not exist.
click.ClickException:
If the configuration file does not exist.
"""
if not mkdocs_yml.exists():
raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}")
@@ -130,10 +152,12 @@ def serve(mkdocs_yml: Path) -> None:
the site when changes are detected.
Args:
mkdocs_yml: Path to the ``mkdocs.yml`` configuration file.
mkdocs_yml (Path):
Path to the `mkdocs.yml` configuration file.
Raises:
click.ClickException: If the configuration file does not exist.
click.ClickException:
If the configuration file does not exist.
"""
if not mkdocs_yml.exists():
raise click.ClickException(f"mkdocs.yml not found: {mkdocs_yml}")

View File

@@ -1,13 +1,14 @@
"""
# Summary
Loader layer for doc-forge.
The ``docforge.loaders`` package is responsible for discovering Python modules
The `docforge.loaders` package is responsible for discovering Python modules
and extracting documentation data using static analysis.
---
Overview
--------
# Overview
This layer converts Python source code into an intermediate documentation
model used by doc-forge. It performs module discovery, introspection, and
@@ -17,9 +18,9 @@ Core capabilities include:
- **Module discovery** Locate Python modules and packages within a project.
- **Static introspection** Parse docstrings, signatures, and object
hierarchies using the ``griffe`` library without executing the code.
hierarchies using the `griffe` library without executing the code.
- **Public API filtering** Exclude private members (names prefixed with
``_``) to produce clean public documentation structures.
`_`) to produce clean public documentation structures.
---
"""

View File

@@ -1,7 +1,9 @@
"""
# Summary
Utilities for loading and introspecting Python modules using Griffe.
This module provides the ``GriffeLoader`` class and helper utilities used to
This module provides the `GriffeLoader` class and helper utilities used to
discover Python modules, introspect their structure, and convert the results
into doc-forge documentation models.
"""
@@ -30,25 +32,30 @@ def discover_module_paths(
"""
Discover Python modules within a package directory.
The function scans the filesystem for ``.py`` files inside the specified
The function scans the filesystem for `.py` files inside the specified
package and converts them into dotted module import paths.
Discovery rules:
- Directories containing ``__init__.py`` are treated as packages.
- Each ``.py`` file is treated as a module.
- Directories containing `__init__.py` are treated as packages.
- Each `.py` file is treated as a module.
- Results are returned as dotted import paths.
Args:
module_name: Top-level package name to discover modules from.
project_root: Root directory used to resolve module paths. If not
provided, the current working directory is used.
module_name (str):
Top-level package name to discover modules from.
project_root (Path, optional):
Root directory used to resolve module paths. If not provided, the
current working directory is used.
Returns:
A sorted list of unique dotted module import paths.
List[str]:
A sorted list of unique dotted module import paths.
Raises:
FileNotFoundError: If the specified package directory does not exist.
FileNotFoundError:
If the specified package directory does not exist.
"""
if project_root is None:
@@ -78,8 +85,8 @@ class GriffeLoader:
Load Python modules using Griffe and convert them into doc-forge models.
This loader uses the Griffe introspection engine to analyze Python source
code and transform the extracted information into ``Project``, ``Module``,
and ``DocObject`` instances used by doc-forge.
code and transform the extracted information into `Project`, `Module`,
and `DocObject` instances used by doc-forge.
"""
def __init__(self) -> None:
@@ -103,24 +110,31 @@ class GriffeLoader:
"""
Load multiple modules and assemble them into a Project model.
Each module path is introspected and converted into a ``Module``
instance. All modules are then aggregated into a single ``Project``
Each module path is introspected and converted into a `Module`
instance. All modules are then aggregated into a single `Project`
object.
Args:
module_paths: List of dotted module import paths to load.
project_name: Optional override for the project name. Defaults
to the top-level name of the first module.
skip_import_errors: If True, modules that fail to load will be
skipped instead of raising an error.
module_paths (List[str]):
List of dotted module import paths to load.
project_name (str, optional):
Optional override for the project name. Defaults to the top-level
name of the first module.
skip_import_errors (bool, optional):
If True, modules that fail to load will be skipped instead of raising an error.
Returns:
A populated ``Project`` instance containing the loaded modules.
Project:
A populated `Project` instance containing the loaded modules.
Raises:
ValueError: If no module paths are provided.
ImportError: If a module fails to load and
``skip_import_errors`` is False.
ValueError:
If no module paths are provided.
ImportError:
If a module fails to load and `skip_import_errors` is False.
"""
if not module_paths:
raise ValueError("At least one module path must be provided")
@@ -148,13 +162,15 @@ class GriffeLoader:
Load and convert a single Python module.
The module is introspected using Griffe and then transformed into
a doc-forge ``Module`` model.
a doc-forge `Module` model.
Args:
path: Dotted import path of the module.
path (str):
Dotted import path of the module.
Returns:
A populated ``Module`` instance.
Module:
A populated `Module` instance.
"""
self._loader.load(path)
griffe_module = self._loader.modules_collection[path]
@@ -170,13 +186,15 @@ class GriffeLoader:
Convert a Griffe module object into a doc-forge Module.
All public members of the module are recursively converted into
``DocObject`` instances.
`DocObject` instances.
Args:
obj: Griffe object representing the module.
obj (Object):
Griffe object representing the module.
Returns:
A populated ``Module`` model.
Module:
A populated `Module` model.
"""
module = Module(
path=obj.path,
@@ -200,10 +218,12 @@ class GriffeLoader:
recursively.
Args:
obj: Griffe object representing a documented Python object.
obj (Object):
Griffe object representing a documented Python object.
Returns:
A ``DocObject`` instance representing the converted object.
DocObject:
A `DocObject` instance representing the converted object.
"""
kind = obj.kind.value
signature = self._safe_signature(obj)
@@ -235,10 +255,12 @@ class GriffeLoader:
Safely extract a docstring from a Griffe object.
Args:
obj: Griffe object to inspect.
obj (Object):
Griffe object to inspect.
Returns:
The raw docstring text if available, otherwise ``None``.
Optional[str]:
The raw docstring text if available, otherwise `None`.
"""
try:
return obj.docstring.value if obj.docstring else None
@@ -250,11 +272,12 @@ class GriffeLoader:
Safely extract the signature of a Griffe object.
Args:
obj: Griffe object to inspect.
obj (Object):
Griffe object to inspect.
Returns:
String representation of the object's signature if available,
otherwise ``None``.
Optional[str]:
String representation of the object's signature if available, otherwise `None`.
"""
try:
if hasattr(obj, "signature") and obj.signature:

View File

@@ -1,13 +1,14 @@
"""
# Summary
Model layer for doc-forge.
The ``docforge.models`` package defines the core data structures used to
The `docforge.models` package defines the core data structures used to
represent Python source code as a structured documentation model.
---
Overview
--------
# Overview
The model layer forms the central intermediate representation used throughout
doc-forge. Python modules and objects discovered during introspection are

View File

@@ -1,8 +1,10 @@
"""
# Summary
Documentation model representing a Python module or package.
This module defines the ``Module`` class used in the doc-forge documentation
model. A ``Module`` acts as a container for top-level documented objects
This module defines the `Module` class used in the doc-forge documentation
model. A `Module` acts as a container for top-level documented objects
(classes, functions, variables, and other members) discovered during
introspection.
"""
@@ -16,15 +18,19 @@ class Module:
"""
Representation of a documented Python module or package.
A ``Module`` stores metadata about the module itself and maintains a
A `Module` stores metadata about the module itself and maintains a
collection of top-level documentation objects discovered during
introspection.
Attributes:
path: Dotted import path of the module.
docstring: Module-level documentation string, if present.
members: Mapping of object names to their corresponding
``DocObject`` representations.
path (str):
Dotted import path of the module.
docstring (Optional[str]):
Module-level documentation string, if present.
members (Dict[str, DocObject]):
Mapping of object names to their corresponding `DocObject` representations.
"""
def __init__(
@@ -36,8 +42,11 @@ class Module:
Initialize a Module instance.
Args:
path: Dotted import path identifying the module.
docstring: Module-level documentation text, if available.
path (str):
Dotted import path identifying the module.
docstring (Optional[str]):
Module-level documentation text, if available.
"""
self.path = path
self.docstring = docstring
@@ -48,8 +57,8 @@ class Module:
Add a documented object to the module.
Args:
obj: Documentation object to register as a top-level
member of the module.
obj (DocObject):
Documentation object to register as a top-level member of the module.
"""
self.members[obj.name] = obj
@@ -58,13 +67,16 @@ class Module:
Retrieve a documented object by name.
Args:
name: Name of the object to retrieve.
name (str):
Name of the object to retrieve.
Returns:
The corresponding ``DocObject`` instance.
DocObject:
The corresponding `DocObject` instance.
Raises:
KeyError: If no object with the given name exists.
KeyError:
If no object with the given name exists.
"""
return self.members[name]
@@ -73,7 +85,7 @@ class Module:
Return all top-level documentation objects in the module.
Returns:
An iterable of ``DocObject`` instances representing the
module's public members.
Iterable[DocObject]:
An iterable of `DocObject` instances representing the module's public members.
"""
return self.members.values()

View File

@@ -1,8 +1,10 @@
"""
# Summary
Documentation model representing individual Python objects.
This module defines the ``DocObject`` class, the fundamental recursive unit of
the doc-forge documentation model. Each ``DocObject`` represents a Python
This module defines the `DocObject` class, the fundamental recursive unit of
the doc-forge documentation model. Each `DocObject` represents a Python
entity such as a class, function, method, or attribute, and may contain nested
members that form a hierarchical documentation structure.
"""
@@ -14,18 +16,28 @@ class DocObject:
"""
Representation of a documented Python object.
A ``DocObject`` models a single Python entity discovered during
A `DocObject` models a single Python entity discovered during
introspection. Objects may contain nested members, allowing the structure
of modules, classes, and other containers to be represented recursively.
Attributes:
name: Local name of the object.
kind: Type of object (for example ``class``, ``function``,
``method``, or ``attribute``).
path: Fully qualified dotted path to the object.
signature: Callable signature if the object represents a callable.
docstring: Raw docstring text extracted from the source code.
members: Mapping of member names to child ``DocObject`` instances.
name (str):
Local name of the object.
kind (str):
Type of object (for example `class`, `function`, `method`, or `attribute`).
path (str):
Fully qualified dotted path to the object.
signature (Optional[str]):
Callable signature if the object represents a callable.
docstring (Optional[str]):
Raw docstring text extracted from the source code.
members (Dict[str, DocObject]):
Mapping of member names to child `DocObject` instances.
"""
def __init__(
@@ -40,11 +52,20 @@ class DocObject:
Initialize a DocObject instance.
Args:
name: Local name of the object.
kind: Object type identifier (for example ``class`` or ``function``).
path: Fully qualified dotted path of the object.
signature: Callable signature if applicable.
docstring: Documentation string associated with the object.
name (str):
Local name of the object.
kind (str):
Object type identifier (for example `class` or `function`).
path (str):
Fully qualified dotted path of the object.
signature (Optional[str]):
Callable signature if applicable.
docstring (Optional[str]):
Documentation string associated with the object.
"""
self.name = name
self.kind = kind
@@ -70,13 +91,16 @@ class DocObject:
Retrieve a member object by name.
Args:
name: Name of the member to retrieve.
name (str):
Name of the member to retrieve.
Returns:
The corresponding ``DocObject`` instance.
DocObject:
The corresponding `DocObject` instance.
Raises:
KeyError: If the member does not exist.
KeyError:
If the member does not exist.
"""
return self.members[name]
@@ -85,6 +109,7 @@ class DocObject:
Return all child members of the object.
Returns:
An iterable of ``DocObject`` instances representing nested members.
Iterable[DocObject]:
An iterable of `DocObject` instances representing nested members.
"""
return self.members.values()

View File

@@ -1,8 +1,10 @@
"""
# Summary
Documentation model representing a project.
This module defines the ``Project`` class, the top-level container used by
doc-forge to represent a documented codebase. A ``Project`` aggregates multiple
This module defines the `Project` class, the top-level container used by
doc-forge to represent a documented codebase. A `Project` aggregates multiple
modules and provides access to them through a unified interface.
"""
@@ -15,12 +17,15 @@ class Project:
"""
Representation of a documentation project.
A ``Project`` serves as the root container for all modules discovered during
A `Project` serves as the root container for all modules discovered during
introspection. Each module is stored by its dotted import path.
Attributes:
name: Name of the project.
modules: Mapping of module paths to ``Module`` instances.
name (str):
Name of the project.
modules (Dict[str, Module]):
Mapping of module paths to `Module` instances.
"""
def __init__(self, name: str) -> None:
@@ -28,7 +33,8 @@ class Project:
Initialize a Project instance.
Args:
name: Name used to identify the documentation project.
name (str):
Name used to identify the documentation project.
"""
self.name = name
self.modules: Dict[str, Module] = {}
@@ -38,7 +44,8 @@ class Project:
Register a module in the project.
Args:
module: Module instance to add to the project.
module (Module):
Module instance to add to the project.
"""
self.modules[module.path] = module
@@ -47,13 +54,16 @@ class Project:
Retrieve a module by its dotted path.
Args:
path: Fully qualified dotted module path (for example ``pkg.module``).
path (str):
Fully qualified dotted module path (for example `pkg.module`).
Returns:
The corresponding ``Module`` instance.
Module:
The corresponding `Module` instance.
Raises:
KeyError: If the module does not exist in the project.
KeyError:
If the module does not exist in the project.
"""
return self.modules[path]
@@ -62,7 +72,8 @@ class Project:
Return all modules contained in the project.
Returns:
An iterable of ``Module`` instances.
Iterable[Module]:
An iterable of `Module` instances.
"""
return self.modules.values()
@@ -71,6 +82,7 @@ class Project:
Return the list of module import paths.
Returns:
A list containing the dotted paths of all modules in the project.
list[str]:
A list containing the dotted paths of all modules in the project.
"""
return list(self.modules.keys())

View File

@@ -1,13 +1,14 @@
"""
# Summary
Renderers layer for doc-forge.
The ``docforge.renderers`` package transforms the internal documentation
The `docforge.renderers` package transforms the internal documentation
models into files formatted for specific documentation systems.
---
Overview
--------
# Overview
Renderers consume the doc-forge project model and generate output suitable
for documentation tools or machine interfaces.
@@ -15,18 +16,17 @@ for documentation tools or machine interfaces.
Current implementations:
- **MkDocsRenderer** Produces Markdown files compatible with MkDocs and
the ``mkdocstrings`` plugin. It automatically handles package hierarchy
and generates ``index.md`` files for packages.
the `mkdocstrings` plugin. It automatically handles package hierarchy
and generates `index.md` files for packages.
- **MCPRenderer** Emits structured JSON resources designed for consumption
by Model Context Protocol (MCP) clients.
---
Extending
---------
# Extending
New renderers can be added by implementing the ``DocRenderer`` protocol
defined in ``docforge.renderers.base``.
New renderers can be added by implementing the `DocRenderer` protocol
defined in `docforge.renderers.base`.
---
"""

View File

@@ -1,9 +1,11 @@
"""
# Summary
Renderer base interfaces and configuration models.
This module defines the base protocol and configuration container used by
doc-forge renderers. Concrete renderer implementations should implement the
``DocRenderer`` protocol.
`DocRenderer` protocol.
"""
from pathlib import Path
@@ -16,12 +18,15 @@ class RendererConfig:
"""
Configuration container for documentation renderers.
A ``RendererConfig`` instance groups together the project model and the
A `RendererConfig` instance groups together the project model and the
output directory used during rendering.
Attributes:
out_dir: Directory where generated documentation files will be written.
project: Documentation project model to be rendered.
out_dir (Path):
Directory where generated documentation files will be written.
project (Project):
Documentation project model to be rendered.
"""
def __init__(self, out_dir: Path, project: Project) -> None:
@@ -29,8 +34,11 @@ class RendererConfig:
Initialize a RendererConfig instance.
Args:
out_dir: Target directory where documentation files should be written.
project: Introspected project model to render.
out_dir (Path):
Target directory where documentation files should be written.
project (Project):
Introspected project model to render.
"""
self.out_dir = out_dir
self.project = project
@@ -41,7 +49,7 @@ class DocRenderer(Protocol):
Protocol defining the interface for documentation renderers.
Implementations of this protocol are responsible for transforming a
``Project`` model into renderer-specific documentation sources.
`Project` model into renderer-specific documentation sources.
"""
name: str
@@ -55,8 +63,10 @@ class DocRenderer(Protocol):
Generate renderer-specific documentation sources.
Args:
project: Project model containing modules and documentation objects.
out_dir: Directory where generated documentation sources
should be written.
project (Project):
Project model containing modules and documentation objects.
out_dir (Path):
Directory where generated documentation sources should be written.
"""
...

View File

@@ -1,3 +1,12 @@
"""
# Summary
MCP renderer implementation.
This module defines the `MCPRenderer` class, which generates documentation
resources compatible with the Model Context Protocol (MCP).
"""
import json
from pathlib import Path
from typing import Dict, List
@@ -21,11 +30,14 @@ class MCPRenderer:
Generate MCP documentation resources for a project.
The renderer serializes each module into a JSON resource and produces
supporting metadata files such as ``nav.json`` and ``index.json``.
supporting metadata files such as `nav.json` and `index.json`.
Args:
project: Documentation project model to render.
out_dir: Directory where MCP resources will be written.
project (Project):
Documentation project model to render.
out_dir (Path):
Directory where MCP resources will be written.
"""
modules_dir = out_dir / "modules"
modules_dir.mkdir(parents=True, exist_ok=True)
@@ -64,8 +76,11 @@ class MCPRenderer:
Serialize a module into an MCP resource file.
Args:
module: Module instance to serialize.
modules_dir: Directory where module JSON files are stored.
module (Module):
Module instance to serialize.
modules_dir (Path):
Directory where module JSON files are stored.
"""
payload = {
"module": module.path,
@@ -81,10 +96,12 @@ class MCPRenderer:
Convert a Module model into MCP-compatible structured data.
Args:
module: Module instance to convert.
module (Module):
Module instance to convert.
Returns:
Dictionary representing the module and its documented objects.
Dict:
Dictionary representing the module and its documented objects.
"""
data: Dict = {
"path": module.path,
@@ -102,10 +119,12 @@ class MCPRenderer:
Recursively convert a DocObject into structured MCP data.
Args:
obj: Documentation object to convert.
obj (DocObject):
Documentation object to convert.
Returns:
Dictionary describing the object and any nested members.
Dict:
Dictionary describing the object and any nested members.
"""
data: Dict = {
"name": obj.name,
@@ -130,9 +149,11 @@ class MCPRenderer:
Serialize data to formatted JSON.
Args:
data: Dictionary to serialize.
data (Dict):
Dictionary to serialize.
Returns:
JSON string formatted with indentation and UTF-8 compatibility.
str:
JSON string formatted with indentation and UTF-8 compatibility.
"""
return json.dumps(data, indent=2, ensure_ascii=False)

View File

@@ -1,16 +1,18 @@
"""
# Summary
MkDocs renderer implementation.
This module defines the ``MkDocsRenderer`` class, which generates Markdown
This module defines the `MkDocsRenderer` class, which generates Markdown
documentation sources compatible with MkDocs Material and the mkdocstrings
plugin.
The renderer ensures a consistent documentation structure by:
- Creating a root ``index.md`` if one does not exist
- Creating a root `index.md` if one does not exist
- Generating package index pages automatically
- Linking child modules within parent package pages
- Optionally generating ``README.md`` from the root package docstring
- Optionally generating `README.md` from the root package docstring
"""
from pathlib import Path
@@ -45,10 +47,15 @@ class MkDocsRenderer:
specified output directory.
Args:
project: Project model containing modules to document.
out_dir: Directory where generated Markdown files will be written.
module_is_source: If True, treat the specified module as the
documentation root rather than nesting it inside a folder.
project (Project):
Project model containing modules to document.
out_dir (Path):
Directory where generated Markdown files will be written.
module_is_source (bool, optional):
If True, treat the specified module as the documentation root
rather than nesting it inside a folder.
"""
out_dir.mkdir(parents=True, exist_ok=True)
self._ensure_root_index(project, out_dir)
@@ -77,19 +84,23 @@ class MkDocsRenderer:
module_is_source: bool | None = None,
) -> None:
"""
Generate a ``README.md`` file from the root module docstring.
Generate a `README.md` file from the root module docstring.
Behavior:
- If ``module_is_source`` is True, ``README.md`` is written to the
project root directory.
- If `module_is_source` is True, `README.md` is written to the project
root directory.
- If False, README generation is currently not implemented.
Args:
project: Project model containing documentation metadata.
docs_dir: Directory containing generated documentation sources.
module_is_source: Whether the module is treated as the project
source root.
project (Project):
Project model containing documentation metadata.
docs_dir (Path):
Directory containing generated documentation sources.
module_is_source (bool, optional):
Whether the module is treated as the project source root.
"""
if not module_is_source:
@@ -136,10 +147,12 @@ class MkDocsRenderer:
Locate the root module corresponding to the project name.
Args:
project: Project model to inspect.
project (Project):
Project model to inspect.
Returns:
The root ``Module`` if found, otherwise ``None``.
Optional[Module]:
The root `Module` if found, otherwise `None`.
"""
for module in project.get_all_modules():
if module.path == project.name:
@@ -156,16 +169,22 @@ class MkDocsRenderer:
"""
Write documentation for a single module.
Package modules are rendered as ``index.md`` files inside their
Package modules are rendered as `index.md` files inside their
corresponding directories, while leaf modules are written as
standalone Markdown pages.
Args:
module: Module to render.
packages: Set of module paths identified as packages.
out_dir: Base directory for generated documentation files.
module_is_source: Whether the module acts as the documentation
root directory.
module (Module):
Module to render.
packages (set[str]):
Set of module paths identified as packages.
out_dir (Path):
Base directory for generated documentation files.
module_is_source (bool, optional):
Whether the module acts as the documentation root directory.
"""
parts = module.path.split(".")
@@ -202,11 +221,15 @@ class MkDocsRenderer:
Generate Markdown content for a module documentation page.
Args:
title: Page title displayed in the documentation.
module_path: Dotted import path of the module.
title (str):
Page title displayed in the documentation.
module_path (str):
Dotted import path of the module.
Returns:
Markdown source containing a mkdocstrings directive.
str:
Markdown source containing a mkdocstrings directive.
"""
return (
f"# {title}\n\n"
@@ -219,11 +242,14 @@ class MkDocsRenderer:
out_dir: Path,
) -> None:
"""
Ensure that the root ``index.md`` page exists.
Ensure that the root `index.md` page exists.
Args:
project: Project model used for the page title.
out_dir: Documentation output directory.
project (Project):
Project model used for the page title.
out_dir (Path):
Documentation output directory.
"""
root_index = out_dir / "index.md"
@@ -246,10 +272,17 @@ class MkDocsRenderer:
child modules.
Args:
parts: Module path components.
out_dir: Documentation output directory.
link_target: Link target used in the parent index.
title: Display title for the link.
parts (list[str]):
Module path components.
out_dir (Path):
Documentation output directory.
link_target (str):
Link target used in the parent index.
title (str):
Display title for the link.
"""
if len(parts) == 1:
parent_index = out_dir / "index.md"

View File

@@ -1,4 +1,6 @@
"""
# Summary
Server layer for doc-forge.
This module exposes server implementations used to provide live access

View File

@@ -1,3 +1,12 @@
"""
# Summary
MCP server implementation.
This module defines the `MCPServer` class, which serves pre-generated
documentation bundles through the Model Context Protocol (MCP).
"""
from __future__ import annotations
import json
@@ -20,10 +29,12 @@ class MCPServer:
Initialize the MCP server.
Args:
mcp_root: Directory containing the generated MCP documentation
bundle (for example ``index.json``, ``nav.json``, and
``modules/``).
name: Identifier used for the MCP server instance.
mcp_root (Path):
Directory containing the generated MCP documentation bundle
(for example `index.json`, `nav.json`, and `modules/`).
name (str):
Identifier used for the MCP server instance.
"""
self.mcp_root = mcp_root
self.app = FastMCP(name)
@@ -43,11 +54,13 @@ class MCPServer:
instead of raising an exception.
Args:
path: Path to the JSON file to read.
path (Path):
Path to the JSON file to read.
Returns:
Parsed JSON data if the file exists, otherwise an error dictionary
describing the missing resource.
Any:
Parsed JSON data if the file exists, otherwise an error dictionary
describing the missing resource.
"""
if not path.exists():
return {
@@ -68,9 +81,9 @@ class MCPServer:
The server exposes documentation resources through the following
endpoints:
- ``docs://index`` Project metadata
- ``docs://nav`` Navigation structure
- ``docs://modules/{module}`` Individual module documentation
- `docs://index` Project metadata
- `docs://nav` Navigation structure
- `docs://modules/{module}` Individual module documentation
"""
@self.app.resource("docs://index")
@@ -116,7 +129,8 @@ class MCPServer:
Start the MCP server.
Args:
transport: Transport mechanism used by the MCP server. Supported
options include ``stdio``, ``sse``, and ``streamable-http``.
transport (Literal["stdio", "sse", "streamable-http"]):
Transport mechanism used by the MCP server. Supported options
include `stdio`, `sse`, and `streamable-http`.
"""
self.app.run(transport=transport)