module.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. from abc import ABC
  2. from pathlib import Path
  3. from typing import Optional, Dict, Any
  4. import logging
  5. from typer import Typer, Option, Argument
  6. from rich.console import Console
  7. from .library import LibraryManager
  8. logger = logging.getLogger(__name__)
  9. console = Console()
  10. class Module(ABC):
  11. """Streamlined base module that auto-detects variables from templates."""
  12. # Required class attributes for subclasses
  13. name = None
  14. description = None
  15. files = None
  16. def __init__(self):
  17. if not all([self.name, self.description, self.files]):
  18. raise ValueError(
  19. f"Module {self.__class__.__name__} must define name, description, and files"
  20. )
  21. logger.info(f"Initializing module '{self.name}'")
  22. logger.debug(f"Module '{self.name}' configuration: files={self.files}, description='{self.description}'")
  23. self.libraries = LibraryManager()
  24. # Initialize variables if the subclass defines _init_variables method
  25. if hasattr(self, '_init_variables'):
  26. logger.debug(f"Module '{self.name}' has variable initialization method")
  27. self._init_variables()
  28. self.metadata = self._build_metadata()
  29. logger.info(f"Module '{self.name}' initialization completed successfully")
  30. def _build_metadata(self) -> Dict[str, Any]:
  31. """Build metadata from class attributes."""
  32. metadata = {}
  33. # Add categories if defined
  34. if hasattr(self, 'categories'):
  35. metadata['categories'] = self.categories
  36. # Add variable metadata if defined
  37. if hasattr(self, 'variable_metadata'):
  38. metadata['variables'] = self.variable_metadata
  39. return metadata
  40. def list(self):
  41. """List all templates."""
  42. logger.debug(f"Listing templates for module '{self.name}'")
  43. templates = self.libraries.find(self.name, self.files, sorted=True)
  44. if templates:
  45. logger.info(f"Listing {len(templates)} templates for module '{self.name}'")
  46. else:
  47. logger.info(f"No templates found for module '{self.name}'")
  48. # Display templates without enrichment (enrichment only needed for generation)
  49. for template in templates:
  50. console.print(f"[cyan]{template.id}[/cyan] - {template.name}")
  51. return templates
  52. def show(self, id: str = Argument(..., help="Template ID")):
  53. """Show template details."""
  54. logger.debug(f"Showing template '{id}' from module '{self.name}'")
  55. # Get template directly from library without enrichment (not needed for display)
  56. template = self.libraries.find_by_id(self.name, self.files, id)
  57. if not template:
  58. logger.debug(f"Template '{id}' not found in module '{self.name}'")
  59. raise FileNotFoundError(f"Template '{id}' not found in module '{self.name}'")
  60. # Header
  61. version = f" v{template.version}" if template.version else ""
  62. console.print(f"[bold magenta]{template.name} ({template.id}{version})[/bold magenta]")
  63. console.print(f"[dim white]{template.description}[/dim white]\n")
  64. # Metadata (only print if exists)
  65. metadata = [
  66. ("Author", template.author),
  67. ("Date", template.date),
  68. ("Tags", ', '.join(template.tags) if template.tags else None)
  69. ]
  70. for label, value in metadata:
  71. if value:
  72. console.print(f"{label}: [cyan]{value}[/cyan]")
  73. # Variables (show raw template variables without module enrichment)
  74. if template.vars:
  75. console.print(f"Variables: [cyan]{', '.join(sorted(template.vars))}[/cyan]")
  76. # Content
  77. if template.content:
  78. print(f"\n{template.content}")
  79. def generate(
  80. self,
  81. id: str = Argument(..., help="Template ID"),
  82. out: Optional[Path] = Option(None, "--out", "-o")
  83. ):
  84. """Generate from template."""
  85. logger.info(f"Starting generation for template '{id}' from module '{self.name}'")
  86. # Fetch template from library
  87. template = self.libraries.find_by_id(self.name, self.files, id)
  88. if not template:
  89. logger.error(f"Template '{id}' not found for generation in module '{self.name}'")
  90. raise FileNotFoundError(f"Template '{id}' not found in module '{self.name}'")
  91. # PLACEHOLDER FOR TEMPLATE GENERATION LOGIC
  92. def register_cli(self, app: Typer):
  93. """Register module commands with the main app."""
  94. logger.debug(f"Registering CLI commands for module '{self.name}'")
  95. module_app = Typer()
  96. module_app.command()(self.list)
  97. module_app.command()(self.show)
  98. module_app.command()(self.generate)
  99. app.add_typer(module_app, name=self.name, help=self.description)
  100. logger.info(f"Module '{self.name}' CLI commands registered")