GeneratorOrchestrator
The GeneratorOrchestrator class discovers, filters, sorts, and executes all registered generators.
Location
from core.generators.orchestrator import GeneratorOrchestrator
Constructor
GeneratorOrchestrator(project_path: Path, config_reader: ConfigReader)
Parameters:
project_path: Path to the project being generatedconfig_reader: ConfigReader instance for accessing configuration
Methods
execute_generators()
Discovers and executes all applicable generators.
def execute_generators(self) -> None
This method:
Discovers all registered generators from
GENERATOR_REGISTRYFilters generators based on
enabled_whenconditionsSorts generators by dependencies and priority
Executes each generator’s
generate()method
Example:
from pathlib import Path
from core.config_reader import ConfigReader
from core.generators.orchestrator import GeneratorOrchestrator
project_path = Path("./my-project")
config_reader = ConfigReader(project_path)
orchestrator = GeneratorOrchestrator(project_path, config_reader)
orchestrator.execute_generators()
Internal Process
1. Discovery
The orchestrator imports generator modules to trigger @Generator decorator registration:
def _discover_generators(self):
# Import all generator modules
from core.generators.configs import *
from core.generators.deployment import *
from core.generators.templates.app import *
from core.generators.templates.database import *
# ... etc
return list(GENERATOR_REGISTRY.values())
2. Filtering
Generators with enabled_when conditions are evaluated:
def _filter_generators(self, generators):
result = []
for gen in generators:
condition = gen.get("enabled_when")
if condition is None or condition(self.config_reader):
result.append(gen)
return result
3. Dependency Resolution
The orchestrator builds a dependency graph and performs topological sorting:
def _resolve_dependencies(self, generators):
# Build adjacency list
graph = {g["class"].__name__: g["requires"] for g in generators}
# Topological sort
sorted_names = self._topological_sort(graph)
# Reorder generators
name_to_gen = {g["class"].__name__: g for g in generators}
return [name_to_gen[name] for name in sorted_names]
4. Priority Sorting
Within dependency constraints, generators are sorted by priority:
def _sort_by_priority(self, generators):
return sorted(generators, key=lambda g: g["priority"])
5. Execution
Each generator is instantiated and executed:
def _execute(self, generators):
for gen_info in generators:
generator = gen_info["class"](
self.project_path,
self.config_reader
)
generator.generate()
Error Handling
Missing Dependency
If a generator requires another generator that doesn’t exist:
@Generator(requires=["NonExistentGenerator"])
class MyGenerator(BaseTemplateGenerator):
...
The orchestrator raises an error during dependency resolution.
Circular Dependency
If generators have circular dependencies:
@Generator(requires=["GeneratorB"])
class GeneratorA(BaseTemplateGenerator): ...
@Generator(requires=["GeneratorA"])
class GeneratorB(BaseTemplateGenerator): ...
The orchestrator detects the cycle and raises an error.
Generator Failure
If a generator’s generate() method raises an exception, the orchestrator stops execution and propagates the error.
Usage in ProjectGenerator
The orchestrator is used by ProjectGenerator:
# core/project_generator.py
class ProjectGenerator:
def __init__(self, project_path: Path, config: dict):
self.project_path = project_path
self.config_reader = ConfigReader(project_path)
self.structure_generator = StructureGenerator(project_path, self.config_reader)
self.orchestrator = GeneratorOrchestrator(project_path, self.config_reader)
def generate(self):
# 1. Create directory structure
self.structure_generator.create_project_structure()
# 2. Execute all generators
self.orchestrator.execute_generators()
Execution Order Example
Given these generators:
@Generator(category="config", priority=1)
class PyprojectGenerator: ...
@Generator(category="database", priority=30, requires=["ConfigDatabaseGenerator"])
class DatabaseConnectionGenerator: ...
@Generator(category="app_config", priority=15)
class ConfigDatabaseGenerator: ...
@Generator(category="model", priority=40, requires=["DatabaseConnectionGenerator"])
class UserModelGenerator: ...
@Generator(category="router", priority=80, requires=["UserModelGenerator"], enabled_when=lambda c: c.has_auth())
class AuthRouterGenerator: ...
With authentication enabled, execution order:
PyprojectGenerator(priority=1, no deps)ConfigDatabaseGenerator(priority=15, no deps)DatabaseConnectionGenerator(priority=30, requires ConfigDatabaseGenerator)UserModelGenerator(priority=40, requires DatabaseConnectionGenerator)AuthRouterGenerator(priority=80, requires UserModelGenerator, auth enabled)
With authentication disabled, AuthRouterGenerator is skipped.
Debugging
List Registered Generators
from core.decorators import GENERATOR_REGISTRY
for name, info in sorted(GENERATOR_REGISTRY.items(), key=lambda x: x[1]["priority"]):
print(f"{info['priority']:3d} | {info['category']:12s} | {name}")
Check Generator Conditions
from core.config_reader import ConfigReader
config_reader = ConfigReader(Path("./project"))
for name, info in GENERATOR_REGISTRY.items():
condition = info.get("enabled_when")
enabled = condition is None or condition(config_reader)
print(f"{name}: {'enabled' if enabled else 'disabled'}")
Trace Execution
Add logging to see execution order:
def execute_generators(self):
generators = self._get_sorted_generators()
for gen_info in generators:
print(f"Executing: {gen_info['class'].__name__}")
generator = gen_info["class"](self.project_path, self.config_reader)
generator.generate()
print(f"Completed: {gen_info['class'].__name__}")