Skip to content

AI bundle creation

Copy this comprehensive prompt into any LLM to get help creating complete Griffonner plugin bundles:

I want to create a Griffonner plugin bundle. Griffonner is a Python documentation generator with an extensible plugin system.

## What I need help with:

Create a complete plugin bundle that includes processors, filters, and templates for [DESCRIBE YOUR USE CASE HERE - e.g., "generating documentation for FastAPI applications", "creating Sphinx-style documentation", "generating GitLab wiki pages"].

## Bundle architecture:

A Griffonner bundle combines:
- **Processors**: Transform Griffe objects before template rendering (add metadata, analyse code, etc.)
- **Filters**: Custom Jinja2 template filters for data formatting
- **Templates**: Jinja2 templates optimised for specific output formats
- **Entry points**: Python packaging configuration for automatic discovery

## Bundle class structure:

```python
from griffonner.plugins import BaseBundle
from typing import Dict, List, Any

class MyBundle(BaseBundle):
    @property
    def name(self) -> str:
        return "my-bundle"

    @property
    def version(self) -> str:
        return "1.0.0"

    @property
    def description(self) -> str:
        return "Description of what this bundle does"

    def get_processors(self) -> Dict[str, Any]:
        """Return processors provided by this bundle."""
        return {
            "processor_name": ProcessorClass(),
        }

    def get_filters(self) -> Dict[str, Any]:
        """Return filters provided by this bundle."""
        return {
            "filter_name": filter_function,
        }

    def get_template_paths(self) -> List[str]:
        """Return template directory paths."""
        return ["templates/my-bundle/"]
```

## Processor example:

```python
from griffonner.plugins import BaseProcessor
from typing import Any, Dict, Tuple, Union
from griffe import Object as GriffeObject, Alias

class MyProcessor(BaseProcessor):
    @property
    def name(self) -> str:
        return "my_processor"

    @property
    def priority(self) -> int:
        return 100  # Default priority

    def process(
        self, 
        griffe_obj: Union[GriffeObject, Alias], 
        context: Dict[str, Any]
    ) -> Tuple[Union[GriffeObject, Alias], Dict[str, Any]]:
        """Transform griffe_obj and add data to context."""

        # Get configuration from frontmatter
        config = context.get("processor_config", {})

        # Analyse the object and add data to context
        analysis_result = self.analyse_object(griffe_obj, config)
        context["my_data"] = analysis_result

        return griffe_obj, context

    def analyse_object(self, obj, config):
        """Your custom analysis logic here."""
        return {"analysed": True, "name": obj.name}
```

## Filter examples:

```python
def format_for_my_platform(text):
    """Format text for specific platform/output."""
    if not text:
        return text
    # Your formatting logic here
    return formatted_text

def create_badge(value, type="info"):
    """Create visual badges for documentation."""
    badges = {
        "info": f"ℹ️ {value}",
        "warning": f"⚠️ {value}", 
        "error": f"❌ {value}",
        "success": f"✅ {value}"
    }
    return badges.get(type, f"📝 {value}")
```

## Template example:

```jinja2
{# templates/my-bundle/module.md.jinja2 #}
# {{ obj.name }}

{{ obj.docstring.summary if obj.docstring }}

{% if my_data %}
**Analysis**: {{ my_data.analysed | create_badge("success") }}
{% endif %}

## Functions

{% for name, func in obj.members.items() if func.kind.value == "function" %}
### {{ func.name }}

{{ func.docstring.summary if func.docstring }}

{% if func.signature %}
**Signature**: {{ func.signature | format_for_my_platform }}
{% endif %}
{% endfor %}
```

## Entry points configuration (pyproject.toml):

```toml
[project.entry-points."griffonner.bundles"]
my-bundle = "my_package:MyBundle"

# Optional: Direct access to components
[project.entry-points."griffonner.processors"]
my_processor = "my_package.processors:MyProcessor"

[project.entry-points."griffonner.filters"]
format_for_my_platform = "my_package.filters:format_for_my_platform"
create_badge = "my_package.filters:create_badge"
```

## Package structure:

```
my-griffonner-bundle/
├── my_bundle/
│   ├── __init__.py          # Export MyBundle
│   ├── bundle.py            # Bundle class
│   ├── processors.py        # Processor classes
│   └── filters.py           # Filter functions
├── templates/
│   └── my-bundle/
│       ├── module.md.jinja2
│       └── class.md.jinja2
├── tests/
│   └── test_bundle.py
├── pyproject.toml
└── README.md
```

## Testing:

```python
def test_my_bundle():
    bundle = MyBundle()

    assert bundle.name == "my-bundle"
    assert "my_processor" in bundle.get_processors()
    assert "format_for_my_platform" in bundle.get_filters()

def test_processor():
    processor = MyProcessor()

    # Mock Griffe object
    from unittest.mock import Mock
    mock_obj = Mock()
    mock_obj.name = "test_module"

    context = {}
    result_obj, result_context = processor.process(mock_obj, context)

    assert "my_data" in result_context
```

## Usage example:

Users install and use the bundle like this:

```shell
pip install my-griffonner-bundle
griffonner bundle my-bundle  # Show bundle info
```

```yaml
# docs/pages/api.md
---
template: "my-bundle/module.md.jinja2"
griffe_target: "myproject.api"
processors:
  enabled: ["my-bundle.my_processor"]
  config:
    custom_setting: "value"
output:
  - filename: "API.md"
    griffe_target: "myproject.api"
---
```

## Griffe object structure:

The griffe_obj parameter contains parsed Python code with these common properties:

- `obj.name` - Object name
- `obj.kind.value` - "module", "class", "function", etc.
- `obj.docstring.summary` - First line of docstring
- `obj.docstring.description` - Full docstring text  
- `obj.members` - Dict of child objects (functions, classes, etc.)
- `obj.signature` - Function signature (for functions)
- `obj.signature.parameters` - List of parameters
- `obj.signature.returns` - Return type annotation
- `obj.decorators` - List of decorators
- `obj.labels` - Set of labels ("property", "classmethod", etc.)

## Please help me create:

1. **Bundle purpose**: [Describe what documentation format/platform you're targeting]
2. **Processors needed**: [What analysis/transformation do you need?]  
3. **Filters needed**: [What formatting/conversion do you need?]
4. **Templates**: [What should the output look like?]
5. **Special requirements**: [Any specific features or constraints?]

Generate the complete bundle code with proper Python packaging, entry points, and example usage.