1
0
Files
PPTX/core/elements.py
lanyuanxiaoyao ed940f0690 refactor: modularize yaml2pptx into layered architecture
Refactor yaml2pptx.py from a 1,245-line monolithic script into a modular
architecture with clear separation of concerns. The entry point is now
127 lines, with business logic distributed across focused modules.

Architecture:
- core/: Domain models (elements, template, presentation)
- loaders/: YAML loading and validation
- renderers/: PPTX and HTML rendering
- preview/: Flask preview server
- utils.py: Shared utilities

Key improvements:
- Element abstraction layer using dataclass with validation
- Renderer logic built into generator classes
- Single-direction dependencies (no circular imports)
- Each module 150-300 lines for better readability
- Backward compatible CLI interface

Documentation:
- README.md: User-facing usage guide
- README_DEV.md: Developer documentation

OpenSpec:
- Archive refactor-yaml2pptx-modular change (63/70 tasks complete)
- Sync 5 delta specs to main specs (2 new + 3 updated)
2026-03-02 16:43:45 +08:00

97 lines
2.7 KiB
Python

"""
元素抽象层模块
定义统一的元素数据类,支持元素验证和未来扩展。
"""
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class TextElement:
"""文本元素"""
type: str = 'text'
content: str = ''
box: list = field(default_factory=lambda: [1, 1, 8, 1])
font: dict = field(default_factory=dict)
def __post_init__(self):
"""创建时验证"""
if not isinstance(self.box, list) or len(self.box) != 4:
raise ValueError("box 必须是包含 4 个数字的列表")
@dataclass
class ImageElement:
"""图片元素"""
type: str = 'image'
src: str = ''
box: list = field(default_factory=lambda: [1, 1, 4, 3])
def __post_init__(self):
"""创建时验证"""
if not self.src:
raise ValueError("图片元素必须指定 src")
if not isinstance(self.box, list) or len(self.box) != 4:
raise ValueError("box 必须是包含 4 个数字的列表")
@dataclass
class ShapeElement:
"""形状元素"""
type: str = 'shape'
shape: str = 'rectangle'
box: list = field(default_factory=lambda: [1, 1, 2, 1])
fill: Optional[str] = None
line: Optional[dict] = None
def __post_init__(self):
"""创建时验证"""
if not isinstance(self.box, list) or len(self.box) != 4:
raise ValueError("box 必须是包含 4 个数字的列表")
@dataclass
class TableElement:
"""表格元素"""
type: str = 'table'
data: list = field(default_factory=list)
position: list = field(default_factory=lambda: [1, 1])
col_widths: list = field(default_factory=list)
style: dict = field(default_factory=dict)
def __post_init__(self):
"""创建时验证"""
if not self.data:
raise ValueError("表格数据不能为空")
if not isinstance(self.position, list) or len(self.position) != 2:
raise ValueError("position 必须是包含 2 个数字的列表")
def create_element(elem_dict: dict):
"""
元素工厂函数,从字典创建对应类型的元素对象
Args:
elem_dict: 元素字典,必须包含 type 字段
Returns:
对应类型的元素对象
Raises:
ValueError: 不支持的元素类型
"""
elem_type = elem_dict.get('type')
if elem_type == 'text':
return TextElement(**elem_dict)
elif elem_type == 'image':
return ImageElement(**elem_dict)
elif elem_type == 'shape':
return ShapeElement(**elem_dict)
elif elem_type == 'table':
return TableElement(**elem_dict)
else:
raise ValueError(f"不支持的元素类型: {elem_type}")