Skip to content

Custom Generator

Generator.templates_path resolves to grace/generators/templates/ inside the installed grace package, so adding a new grace generate <name> command means contributing it to the framework itself — a new module under grace/generators/ plus a template under grace/generators/templates/. This example walks through adding a service generator that scaffolds a plain helper class, following the same shape as the built-in CogGenerator.

1. Add a Template

grace/generators/templates/service/{{ service_module_name }}.py:

class {{ service_name }}:
    def __init__(self):
        pass

2. Write the Generator

grace/generators/service_generator.py:

from logging import info
from re import match

from click.core import Argument
from jinja2_strcase.jinja2_strcase import to_snake

from grace.generator import Generator


class ServiceGenerator(Generator):
    NAME: str = "service"
    OPTIONS: dict = {
        "params": [
            Argument(["name"], type=str),
        ],
    }

    def generate(self, name: str):
        info(f"Creating service '{name}'")

        self.generate_file(
            self.NAME,
            variables={
                "service_name": name,
                "service_module_name": to_snake(name),
            },
            output_dir="bot/helpers",
        )

    def validate(self, name: str, **_kwargs) -> bool:
        """A valid service name must be PascalCase."""
        return bool(match(r"^[A-Z][a-zA-Z0-9]*$", name))


def generator() -> Generator:
    return ServiceGenerator()

Because it lives directly under grace/generators/, register_generators picks it up automatically — no manual registration step.

3. Use It

grace generate service Notifier

Generates bot/helpers/notifier.py:

class Notifier:
    def __init__(self):
        pass

Validating Arguments

validate() runs before generate() and can reject bad input before any files are written — return False (or raise ValidationError) and _generate raises ValidationError on your behalf. See tests/test_generator.py in the repository for a minimal Generator subclass used in Grace's own test suite.