""" Model Generator Generates Pydantic models from framework configuration. """ from pathlib import Path from typing import List from .config_loader import ConfigLoader class ModelGenerator: """Generates Pydantic model files from configuration""" def __init__(self, config: ConfigLoader, output_dir: Path): self.config = config self.output_dir = Path(output_dir) def generate(self): """Generate all model files""" models_dir = self.output_dir / "models" / "pydantic" models_dir.mkdir(parents=True, exist_ok=True) # Generate __init__.py with all models self._generate_models_file(models_dir / "__init__.py") print(f"Generated models in {models_dir}") def _generate_models_file(self, output_path: Path): """Generate the main models file""" # Get component names from config config_comp = self.config.get_shared_component('config') data_comp = self.config.get_shared_component('data') data_flow_sys = self.config.get_system('data_flow') doc_sys = self.config.get_system('documentation') exec_sys = self.config.get_system('execution') connector_comp = self.config.get_component('data_flow', 'connector') pulse_comp = self.config.get_component('data_flow', 'composed') pattern_comp = self.config.get_component('documentation', 'pattern') maps_comp = self.config.get_component('documentation', 'library') doc_composed = self.config.get_component('documentation', 'composed') tool_comp = self.config.get_component('execution', 'utility') monitor_comp = self.config.get_component('execution', 'watcher') cabinet_comp = self.config.get_component('execution', 'container') exec_composed = self.config.get_component('execution', 'composed') # Build the template content = f'''""" Pydantic models - Generated from {self.config.framework.name}.config.json DO NOT EDIT MANUALLY - Regenerate from config """ from enum import Enum from typing import Optional, List, Literal from pydantic import BaseModel, Field class Status(str, Enum): PENDING = "pending" PLANNED = "planned" BUILDING = "building" DEV = "dev" LIVE = "live" READY = "ready" class System(str, Enum): {data_flow_sys.name.upper()} = "{data_flow_sys.name}" {doc_sys.name.upper()} = "{doc_sys.name}" {exec_sys.name.upper()} = "{exec_sys.name}" class ToolType(str, Enum): APP = "app" CLI = "cli" # === Shared Components === class {config_comp.title}(BaseModel): """{config_comp.description}. Shared across {data_flow_sys.name}, {exec_sys.name}.""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None config_path: Optional[str] = None class {data_comp.title}(BaseModel): """{data_comp.description}. Shared across all systems.""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None source_template: Optional[str] = None data_path: Optional[str] = None # === System-Specific Components === class {connector_comp.title}(BaseModel): """{connector_comp.description} ({data_flow_sys.name}).""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None system: Literal["{data_flow_sys.name}"] = "{data_flow_sys.name}" mock: Optional[bool] = None description: Optional[str] = None class {pattern_comp.title}(BaseModel): """{pattern_comp.description} ({doc_sys.name}).""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None template_path: Optional[str] = None system: Literal["{doc_sys.name}"] = "{doc_sys.name}" class {tool_comp.title}(BaseModel): """{tool_comp.description} ({exec_sys.name}).""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None system: Literal["{exec_sys.name}"] = "{exec_sys.name}" type: Optional[ToolType] = None description: Optional[str] = None path: Optional[str] = None url: Optional[str] = None cli: Optional[str] = None class {monitor_comp.title}(BaseModel): """{monitor_comp.description} ({exec_sys.name}).""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None system: Literal["{exec_sys.name}"] = "{exec_sys.name}" class {cabinet_comp.title}(BaseModel): """{cabinet_comp.description} ({exec_sys.name}).""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None tools: List[{tool_comp.title}] = Field(default_factory=list) system: Literal["{exec_sys.name}"] = "{exec_sys.name}" # === Composed Types === class {pulse_comp.title}(BaseModel): """{pulse_comp.description} ({data_flow_sys.name}). Formula: {pulse_comp.formula}.""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None {connector_comp.name}: Optional[{connector_comp.title}] = None {config_comp.name}: Optional[{config_comp.title}] = None {data_comp.name}: Optional[{data_comp.title}] = None system: Literal["{data_flow_sys.name}"] = "{data_flow_sys.name}" class {doc_composed.title}(BaseModel): """{doc_composed.description} ({doc_sys.name}). Formula: {doc_composed.formula}.""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None template: Optional[{pattern_comp.title}] = None {data_comp.name}: Optional[{data_comp.title}] = None output_{data_comp.name}: Optional[{data_comp.title}] = None system: Literal["{doc_sys.name}"] = "{doc_sys.name}" class {exec_composed.title}(BaseModel): """{exec_composed.description} ({exec_sys.name}). Formula: {exec_composed.formula}.""" name: str # Unique identifier slug: str # URL-friendly identifier title: str # Display title for UI status: Optional[Status] = None cabinet: Optional[{cabinet_comp.title}] = None {config_comp.name}: Optional[{config_comp.title}] = None {data_comp.plural}: List[{data_comp.title}] = Field(default_factory=list) system: Literal["{exec_sys.name}"] = "{exec_sys.name}" # === Collection wrappers for JSON files === class {config_comp.title}Collection(BaseModel): items: List[{config_comp.title}] = Field(default_factory=list) class {data_comp.title}Collection(BaseModel): items: List[{data_comp.title}] = Field(default_factory=list) class {connector_comp.title}Collection(BaseModel): items: List[{connector_comp.title}] = Field(default_factory=list) class {pattern_comp.title}Collection(BaseModel): items: List[{pattern_comp.title}] = Field(default_factory=list) class {tool_comp.title}Collection(BaseModel): items: List[{tool_comp.title}] = Field(default_factory=list) class {monitor_comp.title}Collection(BaseModel): items: List[{monitor_comp.title}] = Field(default_factory=list) class {cabinet_comp.title}Collection(BaseModel): items: List[{cabinet_comp.title}] = Field(default_factory=list) class {pulse_comp.title}Collection(BaseModel): items: List[{pulse_comp.title}] = Field(default_factory=list) class {doc_composed.title}Collection(BaseModel): items: List[{doc_composed.title}] = Field(default_factory=list) class {exec_composed.title}Collection(BaseModel): items: List[{exec_composed.title}] = Field(default_factory=list) ''' output_path.write_text(content) if __name__ == "__main__": from .config_loader import load_config # Test with soleprint config config_path = Path(__file__).parent.parent / "soleprint.config.json" config = load_config(config_path) output_dir = Path(__file__).parent.parent / "soleprint-room" generator = ModelGenerator(config, output_dir) generator.generate() print("Models generated successfully!")