2025-08-05 14:38:54 +04:00

102 lines
3.3 KiB
Python

"""
Base Boilerplate Model
======================
This module provides a base class for all L5X models that use boilerplate templates.
"""
import xml.etree.ElementTree as ET
from dataclasses import dataclass
from typing import Optional, Dict
import os
from datetime import datetime
from abc import ABC, abstractmethod
@dataclass
class BaseModuleConfig(ABC):
"""Base configuration for all modules."""
name: str
@abstractmethod
def get_updates(self) -> Dict[str, any]:
"""Get dictionary of updates to apply to the boilerplate."""
pass
class BaseBoilerplateGenerator(ABC):
"""Base generator for L5X files using boilerplate templates."""
def __init__(self, config: BaseModuleConfig):
"""Initialize with configuration."""
self.config = config
self.tree = None
self.root = None
def load_boilerplate(self):
"""Load the boilerplate L5X file."""
if not hasattr(self.config, 'boilerplate_path'):
raise AttributeError("Config must have a boilerplate_path attribute")
if not os.path.exists(self.config.boilerplate_path):
raise FileNotFoundError(f"Boilerplate file not found: {self.config.boilerplate_path}")
self.tree = ET.parse(self.config.boilerplate_path)
self.root = self.tree.getroot()
def update_export_date(self):
"""Update the export date to current time."""
export_date = datetime.now().strftime("%a %b %d %H:%M:%S %Y")
self.root.set("ExportDate", export_date)
@abstractmethod
def apply_updates(self):
"""Apply module-specific updates to the boilerplate."""
pass
def generate(self) -> str:
"""Generate the complete L5X file as a string."""
# Load boilerplate
self.load_boilerplate()
# Apply updates
self.apply_updates()
self.update_export_date()
# Convert to string with proper formatting
return self._to_pretty_xml()
def _to_pretty_xml(self) -> str:
"""Convert the XML tree to a pretty-printed string."""
# Create XML declaration
xml_str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n'
# Add the root element
self._indent(self.root)
xml_str += ET.tostring(self.root, encoding='unicode')
return xml_str
def _indent(self, elem, level=0):
"""Add proper indentation to XML elements."""
i = "\n" + level * " "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for child in elem:
self._indent(child, level + 1)
if not child.tail or not child.tail.strip():
child.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def save_to_file(self, filename: str):
"""Generate and save the L5X content to a file."""
content = self.generate()
with open(filename, 'w', encoding='utf-8') as f:
f.write(content)