1
0
Files
PPTX/loaders/yaml_loader.py
lanyuanxiaoyao 01a93ce13b feat: 添加页面级 enabled 参数支持幻灯片启用/禁用控制
添加页面级 enabled 布尔参数,用于临时禁用整个幻灯片,无需删除或注释 YAML 内容。
与元素级 visible 条件渲染独立工作,提供两层控制机制。

主要变更:
- 在 yaml2pptx.py 主循环中检查 enabled 参数,跳过禁用的幻灯片
- 实现独立的 slide_index 计数器,准确统计实际渲染的幻灯片数量
- 在 yaml_loader.py 中添加 enabled 字段验证,确保类型为布尔值
- 添加 11 个测试用例,覆盖各种使用场景
- 更新 README.md 和 README_DEV.md 文档,说明 enabled 和 visible 的区别
- 创建新的 slide-enabled-control capability 规范
- 更新 template-system 规范,添加 enabled 字段支持

使用示例:
  slides:
    - template: title-slide
      vars:
        title: "正常页面"
    - enabled: false
      template: work-in-progress
      vars:
        title: "临时禁用的页面"

测试:所有 282 个单元测试通过
2026-03-03 16:33:10 +08:00

172 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
YAML 加载和验证模块
负责加载 YAML 文件并验证其结构。
"""
from pathlib import Path
import yaml
# ============= YAML 解析和验证 =============
class YAMLError(Exception):
"""YAML 相关错误"""
pass
def load_yaml_file(file_path):
"""
加载 YAML 文件UTF-8 编码,错误处理)
Args:
file_path: 文件路径(字符串或 Path 对象)
Returns:
解析后的 Python 字典
Raises:
YAMLError: 文件不存在、权限不足、YAML 语法错误等
"""
file_path = Path(file_path)
# 检查文件是否存在
if not file_path.exists():
raise YAMLError(f"文件不存在: {file_path}")
# 检查是否有读取权限
if not file_path.is_file():
raise YAMLError(f"不是有效的文件: {file_path}")
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
return data
except PermissionError:
raise YAMLError(f"权限不足,无法读取文件: {file_path}")
except yaml.YAMLError as e:
# 提取行号信息
if hasattr(e, 'problem_mark'):
mark = e.problem_mark
raise YAMLError(
f"YAML 语法错误: {file_path}, 第 {mark.line + 1} 行: {e.problem}"
)
else:
raise YAMLError(f"YAML 解析错误: {file_path}: {str(e)}")
except Exception as e:
raise YAMLError(f"读取文件失败: {file_path}: {str(e)}")
def validate_presentation_yaml(data, file_path=""):
"""
验证演示文稿 YAML 结构必需字段slides
Args:
data: 解析后的 YAML 数据
file_path: 文件路径(用于错误消息)
Raises:
YAMLError: 结构验证失败
"""
if not isinstance(data, dict):
raise YAMLError(f"{file_path}: 演示文稿必须是一个字典对象")
# 验证 slides 字段
if 'slides' not in data:
raise YAMLError(f"{file_path}: 缺少必需字段 'slides'")
if not isinstance(data['slides'], list):
raise YAMLError(f"{file_path}: 'slides' 必须是一个列表")
# 验证每个幻灯片的 enabled 字段
for i, slide in enumerate(data['slides']):
if isinstance(slide, dict) and 'enabled' in slide:
if not isinstance(slide['enabled'], bool):
raise YAMLError(
f"{file_path}: slides[{i}].enabled 必须是布尔值true 或 false"
f"不支持字符串或条件表达式"
)
# 验证 templates 字段(内联模板)
validate_templates_yaml(data, file_path)
def validate_template_yaml(data, file_path=""):
"""
验证模板 YAML 结构vars, elements
Args:
data: 解析后的 YAML 数据
file_path: 文件路径(用于错误消息)
Raises:
YAMLError: 结构验证失败
"""
if not isinstance(data, dict):
raise YAMLError(f"{file_path}: 模板必须是一个字典对象")
# 验证 vars 字段
if 'vars' in data:
if not isinstance(data['vars'], list):
raise YAMLError(f"{file_path}: 'vars' 必须是一个列表")
# 验证每个变量定义
for i, var_def in enumerate(data['vars']):
if not isinstance(var_def, dict):
raise YAMLError(f"{file_path}: vars[{i}] 必须是一个字典对象")
if 'name' not in var_def:
raise YAMLError(f"{file_path}: vars[{i}] 缺少必需字段 'name'")
# 验证 elements 字段
if 'elements' not in data:
raise YAMLError(f"{file_path}: 缺少必需字段 'elements'")
if not isinstance(data['elements'], list):
raise YAMLError(f"{file_path}: 'elements' 必须是一个列表")
def validate_templates_yaml(data, file_path=""):
"""
验证 templates 字段结构(内联模板)
Args:
data: 解析后的 YAML 数据
file_path: 文件路径(用于错误消息)
Raises:
YAMLError: 结构验证失败
"""
# 验证 templates 字段是否为字典
if 'templates' in data:
if not isinstance(data['templates'], dict):
raise YAMLError(f"{file_path}: 'templates' 必须是一个字典")
# 验证每个内联模板的结构
for template_name, template_data in data['templates'].items():
# 构建模板位置路径
template_location = f"{file_path}.templates.{template_name}"
# 验证模板是字典
if not isinstance(template_data, dict):
raise YAMLError(f"{template_location}: 模板定义必须是字典")
# 验证必需的 elements 字段
if 'elements' not in template_data:
raise YAMLError(f"{template_location}: 缺少必需字段 'elements'")
if not isinstance(template_data['elements'], list):
raise YAMLError(f"{template_location}: 'elements' 必须是一个列表")
# 验证可选的 vars 字段
if 'vars' in template_data:
if not isinstance(template_data['vars'], list):
raise YAMLError(f"{template_location}: 'vars' 必须是一个列表")
# 验证每个变量定义
for i, var_def in enumerate(template_data['vars']):
if not isinstance(var_def, dict):
raise YAMLError(f"{template_location}.vars[{i}]: 变量定义必须是字典")
# 验证必需的 name 字段
if 'name' not in var_def:
raise YAMLError(f"{template_location}.vars[{i}]: 缺少必需字段 'name'")