Skip to content

Complete Examples

Real-world examples of using Plating for documentation generation.

Full Provider Documentation

Complete workflow for documenting an entire provider:

#!/usr/bin/env python3
"""
generate_docs.py - Generate complete provider documentation
"""
import asyncio
import sys
from pathlib import Path
from plating import Plating, PlatingContext
from plating.types import ComponentType
from provide.foundation import logger, pout, perr

async def generate_provider_docs():
    """Generate documentation for entire provider."""

    # Configure context
    context = PlatingContext(
        provider_name="mycloud",
        log_level="INFO",
        no_color=False
    )

    # Initialize API
    api = Plating(context, package_name="pyvider.mycloud")

    pout("🚀 Starting documentation generation for mycloud provider")

    # Step 1: Create templates for undocumented components
    pout("\n📝 Creating documentation templates...")
    adorn_result = await api.adorn()

    if adorn_result.templates_generated > 0:
        pout(f"✅ Created {adorn_result.templates_generated} new templates")
        pout(f"   Components processed: {adorn_result.components_processed}")
    else:
        pout("ℹ️  All components already have templates")

    # Step 2: Generate documentation (validation runs automatically)
    pout("\n📄 Generating documentation...")
    plate_result = await api.plate(
        output_dir=Path("docs"),
        validate_markdown=True,  # Validates during generation
        force=True  # Overwrite existing files
    )

    if plate_result.success:
        pout(f"✅ Generated {plate_result.files_generated} documentation files")
        for file in plate_result.output_files[:5]:  # Show first 5
            pout(f"   • {file}")
        if len(plate_result.output_files) > 5:
            pout(f"   • ... and {len(plate_result.output_files) - 5} more")
    else:
        perr("❌ Documentation generation failed")
        for error in plate_result.errors:
            perr(f"   • {error}")
        return False

    # Note: validate_markdown=True already validated during generation
    # Optional: Run standalone validation if you need additional checks
    # validate_result = await api.validate(output_dir=Path("docs"))

    # Step 3: Generate statistics
    stats = api.get_registry_stats()  # Note: This is a sync method, not async
    pout(f"\n📈 Documentation Coverage:")
    pout(f"   • Resources: {stats['resource']['total']} total, {stats['resource']['with_templates']} with docs")
    pout(f"   • Data Sources: {stats['data_source']['total']} total, {stats['data_source']['with_templates']} with docs")
    pout(f"   • Functions: {stats['function']['total']} total, {stats['function']['with_templates']} with docs")

    pout(f"\n✨ Documentation generation complete!")
    return True

if __name__ == "__main__":
    success = asyncio.run(generate_provider_docs())
    sys.exit(0 if success else 1)

Multi-Provider Batch Processing

Process multiple providers in parallel:

#!/usr/bin/env python3
"""
batch_docs.py - Generate docs for multiple providers
"""
import asyncio
from pathlib import Path
from typing import List, Tuple
from plating import Plating, PlatingContext
from plating.types import PlateResult

async def process_provider(
    provider_name: str,
    package_name: str
) -> Tuple[str, PlateResult]:
    """Process a single provider."""

    context = PlatingContext(
        provider_name=provider_name,
        quiet=True  # Suppress output for parallel processing
    )

    api = Plating(context, package_name=package_name)

    # Generate docs
    output_dir = Path(f"docs/{provider_name}")
    result = await api.plate(output_dir=output_dir)

    return provider_name, result

async def batch_process():
    """Process multiple providers in parallel."""

    providers = [
        ("aws", "pyvider.aws"),
        ("azure", "pyvider.azure"),
        ("gcp", "pyvider.gcp"),
        ("kubernetes", "pyvider.kubernetes"),
    ]

    print(f"Processing {len(providers)} providers...")

    # Process all providers in parallel
    tasks = [
        process_provider(name, package)
        for name, package in providers
    ]

    results = await asyncio.gather(*tasks, return_exceptions=True)

    # Report results
    for provider_name, result in results:
        if isinstance(result, Exception):
            print(f"❌ {provider_name}: Failed - {result}")
        elif isinstance(result, PlateResult):
            if result.success:
                print(f"✅ {provider_name}: {result.files_generated} files")
            else:
                print(f"❌ {provider_name}: Failed with {len(result.errors)} errors")

if __name__ == "__main__":
    asyncio.run(batch_process())

CI/CD Integration

GitHub Actions workflow example:

#!/usr/bin/env python3
"""
ci_docs.py - CI/CD documentation generation script
"""
import asyncio
import os
import sys
from pathlib import Path
from plating import Plating, PlatingContext

async def ci_generate_docs():
    """Generate docs for CI/CD pipeline."""

    # Get configuration from environment
    provider_name = os.environ.get("PROVIDER_NAME", "myprovider")
    package_name = os.environ.get("PACKAGE_NAME", "pyvider.myprovider")
    output_dir = Path(os.environ.get("DOCS_OUTPUT", "docs"))

    # CI-optimized context
    context = PlatingContext(
        provider_name=provider_name,
        no_color=True,  # No colors in CI logs
        verbose=True    # Detailed output for debugging
    )

    api = Plating(context, package_name=package_name)

    # Generate documentation
    result = await api.plate(
        output_dir=output_dir,
        validate_markdown=True,
        force=True
    )

    if not result.success:
        print(f"::error::Documentation generation failed")
        for error in result.errors:
            print(f"::error::{error}")
        return 1

    # Validate
    validate_result = await api.validate(output_dir=output_dir)

    if validate_result.failed > 0:
        print(f"::warning::{validate_result.failed} files failed validation")
        return 1

    print(f"::notice::Generated {result.files_generated} documentation files")
    return 0

if __name__ == "__main__":
    exit_code = asyncio.run(ci_generate_docs())
    sys.exit(exit_code)

Custom Template Functions

Add custom functions to templates:

#!/usr/bin/env python3
"""
custom_functions.py - Custom template functions
"""
import asyncio
from datetime import datetime
from pathlib import Path
from plating import Plating, PlatingContext
from plating.templating.engine import template_engine

def format_date(date_str: str) -> str:
    """Format date for documentation."""
    dt = datetime.fromisoformat(date_str)
    return dt.strftime("%B %d, %Y")

def terraform_version(version: str) -> str:
    """Format Terraform version requirement."""
    return f"Terraform >= {version}"

async def generate_with_custom_functions():
    """Generate docs with custom template functions."""

    context = PlatingContext(provider_name="myprovider")
    api = Plating(context)

    # Add custom functions to the global template engine
    template_engine._jinja_env.globals.update({
        "format_date": format_date,
        "tf_version": terraform_version,
        "provider_version": lambda: "1.2.3",
        "copyright_year": lambda: datetime.now().year,
    })

    # Now templates can use:
    # {{ format_date("2024-01-01") }}
    # {{ tf_version("1.0") }}
    # {{ provider_version() }}
    # {{ copyright_year() }}

    result = await api.plate()
    return result

asyncio.run(generate_with_custom_functions())

Selective Component Processing

Process specific components:

#!/usr/bin/env python3
"""
selective_docs.py - Generate docs for specific components
"""
import asyncio
from plating import Plating, PlatingContext
from plating.types import ComponentType

async def selective_generation():
    """Generate docs for specific component types."""

    context = PlatingContext(provider_name="myprovider")
    api = Plating(context, package_name="pyvider.myprovider")

    # Only process resources
    print("Processing resources...")
    resource_result = await api.plate(
        component_types=[ComponentType.RESOURCE]
    )
    print(f"Generated {resource_result.files_generated} resource docs")

    # Only process data sources
    print("Processing data sources...")
    data_result = await api.plate(
        component_types=[ComponentType.DATA_SOURCE]
    )
    print(f"Generated {data_result.files_generated} data source docs")

    # Process specific components by filtering
    registry = api.registry
    vpc_resources = [
        r for r in registry.get_components(ComponentType.RESOURCE)
        if "vpc" in r.name.lower()
    ]
    print(f"Found {len(vpc_resources)} VPC-related resources")

asyncio.run(selective_generation())

Error Handling

Comprehensive error handling:

#!/usr/bin/env python3
"""
robust_docs.py - Robust documentation generation with error handling
"""
import asyncio
import logging
from pathlib import Path
from plating import Plating, PlatingContext
from plating.errors import (
    PlatingError,
    TemplateError,
    FileSystemError,
    ValidationError
)

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

async def robust_generation():
    """Generate docs with comprehensive error handling."""

    try:
        context = PlatingContext(
            provider_name="myprovider",
            log_level="DEBUG"
        )
        api = Plating(context, package_name="pyvider.myprovider")

        # Attempt documentation generation
        result = await api.plate(output_dir=Path("docs"))

        if result.success:
            logger.info(f"Success! Generated {result.files_generated} files")
        else:
            logger.error(f"Failed with {len(result.errors)} errors")
            for error in result.errors:
                logger.error(f"  - {error}")

    except TemplateError as e:
        logger.error(f"Template error in {e.template_path}:{e.line_number}")
        logger.error(f"  Reason: {e.reason}")
        if e.template_context:
            logger.error(f"  Context: {e.template_context}")
        return False

    except FileSystemError as e:
        logger.error(f"File system error with {e.path}")
        logger.error(f"  Operation: {e.operation}")
        logger.error(f"  Reason: {e.reason}")
        if e.caused_by:
            logger.error(f"  Caused by: {e.caused_by}")
        return False

    except ValidationError as e:
        logger.error(f"Validation error: {e.validation_name}")
        logger.error(f"  Reason: {e.reason}")
        if e.file_path:
            logger.error(f"  File: {e.file_path}")
        for failure in e.failures:
            logger.error(f"  - {failure}")
        return False

    except PlatingError as e:
        logger.error(f"Plating error: {e}")
        return False

    except Exception as e:
        logger.exception(f"Unexpected error: {e}")
        return False

    return True

if __name__ == "__main__":
    success = asyncio.run(robust_generation())
    exit(0 if success else 1)

Testing Documentation

Test harness for documentation:

#!/usr/bin/env python3
"""
test_docs.py - Test documentation generation
"""
import asyncio
import tempfile
from pathlib import Path
from plating import Plating, PlatingContext

async def test_documentation():
    """Test documentation generation in temp directory."""

    with tempfile.TemporaryDirectory() as tmpdir:
        output_dir = Path(tmpdir) / "docs"

        context = PlatingContext(
            provider_name="testprovider",
            quiet=True
        )
        api = Plating(context, package_name="pyvider.testprovider")

        # Test adorning
        adorn_result = await api.adorn()
        assert adorn_result.errors == []

        # Test plating
        plate_result = await api.plate(output_dir=output_dir)
        assert plate_result.success
        assert plate_result.files_generated > 0

        # Verify files exist
        for file in plate_result.output_files:
            assert file.exists(), f"Missing: {file}"

        # Test validation
        validate_result = await api.validate(output_dir=output_dir)
        assert validate_result.failed == 0

        print("✅ All tests passed!")

asyncio.run(test_documentation())

Custom Bundle Creation

Programmatically create bundles:

#!/usr/bin/env python3
"""
create_bundle.py - Create custom documentation bundles
"""
import asyncio
from pathlib import Path
from plating.bundles import PlatingBundle

async def create_custom_bundle():
    """Create a custom plating bundle."""

    # Create bundle directory structure
    bundle_dir = Path("my_resource.plating")
    bundle_dir.mkdir(exist_ok=True)
    (bundle_dir / "docs").mkdir(exist_ok=True)
    (bundle_dir / "examples").mkdir(exist_ok=True)
    (bundle_dir / "fixtures").mkdir(exist_ok=True)

    # Create main template
    template = """---
page_title: "Resource: myprovider_my_resource"
description: "Manages a my_resource in MyProvider"
---

# myprovider_my_resource

Manages a my_resource in the MyProvider infrastructure.

## Example Usage

{{ example("basic") }}

## Schema

{{ schema() }}

## Import

```bash
terraform import myprovider_my_resource.example <id>
"""

(bundle_dir / "docs" / "my_resource.tmpl.md").write_text(template)

# Create example
example = '''resource "myprovider_my_resource" "example" {

name = "example-resource" description = "Created by Plating"

configuration { setting = "value" } }'''

(bundle_dir / "examples" / "basic.tf").write_text(example)

# Create bundle instance
bundle = PlatingBundle(
    name="my_resource",
    plating_dir=bundle_dir,
    component_type="resource"
)

print(f"Created bundle: {bundle.name}")
print(f"  Docs: {bundle.docs_dir}")
print(f"  Examples: {bundle.examples_dir}")
print(f"  Has template: {bundle.has_main_template()}")

asyncio.run(create_custom_bundle()) ```