1
0
Files
PPTX/validators/validator.py
lanyuanxiaoyao 83ff827ad1 feat: add YAML validation with check command and auto-validation
Implements comprehensive validation before PPTX conversion to catch errors early. Includes element-level validation (colors, fonts, table consistency) and system-level validation (geometry, resources). Supports standalone check command and automatic validation during conversion.
2026-03-02 18:14:45 +08:00

161 lines
5.4 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 文件验证。
"""
from pathlib import Path
from loaders.yaml_loader import load_yaml_file, validate_presentation_yaml, YAMLError
from validators.result import ValidationResult, ValidationIssue
from validators.geometry import GeometryValidator
from validators.resource import ResourceValidator
from core.elements import create_element
class Validator:
"""主验证器"""
# 幻灯片尺寸映射(英寸)
SLIDE_SIZES = {
"16:9": (10, 5.625),
"4:3": (10, 7.5),
}
def __init__(self):
"""初始化验证器"""
pass
def validate(self, yaml_path: Path, template_dir: Path = None) -> ValidationResult:
"""
验证 YAML 文件
Args:
yaml_path: YAML 文件路径
template_dir: 模板文件目录(可选)
Returns:
验证结果
"""
errors = []
warnings = []
infos = []
# 1. 加载 YAML
try:
data = load_yaml_file(yaml_path)
validate_presentation_yaml(data, str(yaml_path))
except YAMLError as e:
errors.append(ValidationIssue(
level="ERROR",
message=str(e),
location="",
code="YAML_ERROR"
))
return ValidationResult(
valid=False,
errors=errors,
warnings=warnings,
infos=infos
)
except Exception as e:
errors.append(ValidationIssue(
level="ERROR",
message=f"加载 YAML 文件失败: {str(e)}",
location="",
code="YAML_LOAD_ERROR"
))
return ValidationResult(
valid=False,
errors=errors,
warnings=warnings,
infos=infos
)
# 获取幻灯片尺寸
size_str = data.get('metadata', {}).get('size', '16:9')
slide_width, slide_height = self.SLIDE_SIZES.get(size_str, (10, 5.625))
# 初始化子验证器
geometry_validator = GeometryValidator(slide_width, slide_height)
resource_validator = ResourceValidator(
yaml_dir=yaml_path.parent,
template_dir=template_dir
)
# 2. 验证每个幻灯片
slides = data.get('slides', [])
for slide_index, slide_data in enumerate(slides, start=1):
# 验证模板
template_issues = resource_validator.validate_template(slide_data, slide_index)
self._categorize_issues(template_issues, errors, warnings, infos)
# 验证元素
elements = slide_data.get('elements', [])
for elem_index, elem_dict in enumerate(elements, start=1):
# 3. 元素级验证
try:
element = create_element(elem_dict)
# 调用元素的 validate() 方法
if hasattr(element, 'validate'):
elem_issues = element.validate()
# 填充位置信息
for issue in elem_issues:
issue.location = f"幻灯片 {slide_index}, 元素 {elem_index}"
self._categorize_issues(elem_issues, errors, warnings, infos)
# 4. 几何验证
geom_issues = geometry_validator.validate_element(
element, slide_index, elem_index
)
self._categorize_issues(geom_issues, errors, warnings, infos)
# 5. 资源验证(图片)
if elem_dict.get('type') == 'image':
img_issues = resource_validator.validate_image(
element, slide_index, elem_index
)
self._categorize_issues(img_issues, errors, warnings, infos)
except ValueError as e:
# 元素创建失败__post_init__ 中的验证)
errors.append(ValidationIssue(
level="ERROR",
message=str(e),
location=f"幻灯片 {slide_index}, 元素 {elem_index}",
code="ELEMENT_VALIDATION_ERROR"
))
except Exception as e:
errors.append(ValidationIssue(
level="ERROR",
message=f"验证元素时出错: {str(e)}",
location=f"幻灯片 {slide_index}, 元素 {elem_index}",
code="ELEMENT_VALIDATION_ERROR"
))
# 返回验证结果
return ValidationResult(
valid=len(errors) == 0,
errors=errors,
warnings=warnings,
infos=infos
)
def _categorize_issues(self, issues: list, errors: list, warnings: list, infos: list):
"""
将问题按级别分类
Args:
issues: 问题列表
errors: 错误列表
warnings: 警告列表
infos: 提示列表
"""
for issue in issues:
if issue.level == "ERROR":
errors.append(issue)
elif issue.level == "WARNING":
warnings.append(issue)
elif issue.level == "INFO":
infos.append(issue)