refactor: 移除 doc 和 ppt reader 支持

移除对旧版 .doc 和 .ppt 格式的支持,以简化项目架构和减少维护负担。

变更内容:
- 删除 scripts/readers/doc/ 目录
- 删除 scripts/readers/ppt/ 目录
- 从 readers/__init__.py 中移除 DocReader 和 PptReader
- 从 utils/file_detection.py 中移除 is_valid_doc 和 is_valid_ppt
- 从 config.py 中移除 doc 和 ppt 依赖配置
- 从 advice_generator.py 中移除相关映射
- 更新 CLI 帮助文档
- 更新 README.md 文档
- 删除相关测试用例
- 删除相关规范文档
This commit is contained in:
2026-03-11 00:55:15 +08:00
parent fad0edc46a
commit 65c746c639
22 changed files with 9 additions and 564 deletions

View File

@@ -1,6 +1,6 @@
# lyxy-document # lyxy-document
统一文档解析工具 - 将 DOC、DOCX、XLS、XLSX、PPT、PPTX、PDF、HTML/URL 转换为 Markdown 统一文档解析工具 - 将 DOCX、XLS、XLSX、PPTX、PDF、HTML/URL 转换为 Markdown
## 项目概述 ## 项目概述
@@ -25,11 +25,9 @@ scripts/
│ └── exceptions.py # 异常定义 │ └── exceptions.py # 异常定义
├── readers/ # 格式阅读器 ├── readers/ # 格式阅读器
│ ├── base.py # Reader 基类 │ ├── base.py # Reader 基类
│ ├── doc/ # DOC 解析器(旧格式)
│ ├── docx/ # DOCX 解析器 │ ├── docx/ # DOCX 解析器
│ ├── xls/ # XLS 解析器(旧格式) │ ├── xls/ # XLS 解析器(旧格式)
│ ├── xlsx/ # XLSX 解析器 │ ├── xlsx/ # XLSX 解析器
│ ├── ppt/ # PPT 解析器(旧格式)
│ ├── pptx/ # PPTX 解析器 │ ├── pptx/ # PPTX 解析器
│ ├── pdf/ # PDF 解析器 │ ├── pdf/ # PDF 解析器
│ └── html/ # HTML/URL 解析器 │ └── html/ # HTML/URL 解析器
@@ -40,9 +38,7 @@ scripts/
tests/ # 测试套件 tests/ # 测试套件
├── test_readers/ # Reader 测试 ├── test_readers/ # Reader 测试
│ └── fixtures/ # 静态测试文件Git LFS 管理) │ └── fixtures/ # 静态测试文件Git LFS 管理)
── doc/ # DOC 旧格式测试文件 ── xls/ # XLS 旧格式测试文件
│ ├── xls/ # XLS 旧格式测试文件
│ └── ppt/ # PPT 旧格式测试文件
openspec/ # OpenSpec 规范文档 openspec/ # OpenSpec 规范文档
README.md # 本文档(开发者文档) README.md # 本文档(开发者文档)
SKILL.md # AI Skill 文档 SKILL.md # AI Skill 文档
@@ -52,7 +48,7 @@ SKILL.md # AI Skill 文档
### 静态测试文件目录 ### 静态测试文件目录
`tests/test_readers/fixtures/` 目录用于存放**预先准备的静态测试文件**,特别是难以通过 Python 自动化创建的旧格式文件(.doc/.xls/.ppt)。 `tests/test_readers/fixtures/` 目录用于存放**预先准备的静态测试文件**,特别是难以通过 Python 自动化创建的旧格式文件(.xls)。
### 目录使用规则 ### 目录使用规则
@@ -64,8 +60,8 @@ SKILL.md # AI Skill 文档
`tests/test_readers/conftest.py` 提供以下静态文件 fixtures `tests/test_readers/conftest.py` 提供以下静态文件 fixtures
- 目录路径:`doc_fixture_path``xls_fixture_path``ppt_fixture_path` - 目录路径:`xls_fixture_path`
- 单个文件:`simple_doc_path``with_headings_doc_path``with_table_doc_path` - 单个文件:`simple_xls_path`
文件不存在时会自动 `pytest.skip()`,保证 CI 稳定性。 文件不存在时会自动 `pytest.skip()`,保证 CI 稳定性。
@@ -224,15 +220,6 @@ uv run \
pytest tests/test_readers/test_html/ pytest tests/test_readers/test_html/
``` ```
#### 测试 DOC reader旧格式使用静态文件
```bash
uv run \
--with pytest \
--with "markitdown[docx]" \
--with pypandoc-binary \
pytest tests/test_readers/test_doc/
```
#### 测试 XLS reader旧格式使用静态文件 #### 测试 XLS reader旧格式使用静态文件
```bash ```bash
uv run \ uv run \
@@ -245,14 +232,6 @@ uv run \
pytest tests/test_readers/test_xls/ pytest tests/test_readers/test_xls/
``` ```
#### 测试 PPT reader旧格式使用静态文件
```bash
uv run \
--with pytest \
--with "markitdown[pptx]" \
pytest tests/test_readers/test_ppt/
```
#### 运行特定测试文件或方法 #### 运行特定测试文件或方法
```bash ```bash
# 运行特定测试文件CLI 测试无需额外依赖) # 运行特定测试文件CLI 测试无需额外依赖)

View File

@@ -1,68 +0,0 @@
## Purpose
DOC 文档解析能力,支持解析 Microsoft Word 97-2003 旧格式文档。
## Requirements
### Requirement: DOC 文档解析
系统 SHALL 支持解析 .doc 格式文档,按优先级尝试多个解析器。
#### Scenario: 按优先级尝试解析器
- **WHEN** 解析 DOC 文档
- **THEN** 系统按 markitdown → pypandoc-binary 的顺序尝试
#### Scenario: 成功解析
- **WHEN** 任一解析器成功
- **THEN** 系统返回解析结果
#### Scenario: 所有解析器失败
- **WHEN** 所有解析器均失败
- **THEN** 系统返回失败列表并退出非零状态码
### Requirement: markitdown 解析器
系统 SHALL 支持使用 markitdown 库解析 DOC。
#### Scenario: markitdown 解析成功
- **WHEN** markitdown 库可用且文档有效
- **THEN** 系统返回 Markdown 内容
#### Scenario: markitdown 库未安装
- **WHEN** markitdown 库未安装
- **THEN** 系统尝试下一个解析器
### Requirement: pypandoc-binary 解析器
系统 SHALL 支持使用 pypandoc-binary 库解析 DOC。
#### Scenario: pypandoc 解析成功
- **WHEN** pypandoc-binary 库可用且文档有效
- **THEN** 系统返回 Markdown 内容
#### Scenario: pypandoc-binary 库未安装
- **WHEN** pypandoc-binary 库未安装
- **THEN** 系统尝试下一个解析器
### Requirement: 每个解析器独立文件
系统 SHALL 将每个解析器实现为独立的单文件模块。
#### Scenario: markitdown 解析器在独立文件
- **WHEN** 使用 markitdown 解析器
- **THEN** 从 readers/doc/markitdown.py 导入
#### Scenario: pypandoc 解析器在独立文件
- **WHEN** 使用 pypandoc 解析器
- **THEN** 从 readers/doc/pypandoc.py 导入
### Requirement: DOC Reader 测试使用静态文件
DOC Reader 测试 MUST 使用 `tests/test_readers/fixtures/doc/` 下的静态文件。
#### Scenario: 测试使用 simple.doc
- **WHEN** 测试 DOC Reader 基础解析能力
- **THEN** 使用 `simple.doc` 静态文件
#### Scenario: 测试使用 with_headings.doc
- **WHEN** 测试 DOC Reader 标题解析
- **THEN** 使用 `with_headings.doc` 静态文件
#### Scenario: 测试使用 with_table.doc
- **WHEN** 测试 DOC Reader 表格解析
- **THEN** 使用 `with_table.doc` 静态文件

View File

@@ -1,53 +0,0 @@
## Purpose
PPT 文档解析能力,支持解析 Microsoft PowerPoint 97-2003 旧格式文档。
## Requirements
### Requirement: PPT 文档解析
系统 SHALL 支持解析 .ppt 格式文档,按优先级尝试多个解析器。
#### Scenario: 按优先级尝试解析器
- **WHEN** 解析 PPT 文档
- **THEN** 系统按 markitdown 的顺序尝试
#### Scenario: 成功解析
- **WHEN** 任一解析器成功
- **THEN** 系统返回解析结果
#### Scenario: 所有解析器失败
- **WHEN** 所有解析器均失败
- **THEN** 系统返回失败列表并退出非零状态码
### Requirement: markitdown 解析器
系统 SHALL 支持使用 markitdown 库解析 PPT。
#### Scenario: markitdown 解析成功
- **WHEN** markitdown 库可用且文档有效
- **THEN** 系统返回 Markdown 内容
#### Scenario: markitdown 库未安装
- **WHEN** markitdown 库未安装
- **THEN** 系统返回失败信息
### Requirement: 每个解析器独立文件
系统 SHALL 将每个解析器实现为独立的单文件模块。
#### Scenario: markitdown 解析器在独立文件
- **WHEN** 使用 markitdown 解析器
- **THEN** 从 readers/ppt/markitdown.py 导入
### Requirement: PPT Reader 测试使用静态文件
PPT Reader 测试 MUST 使用 `tests/test_readers/fixtures/ppt/` 下的静态文件。
#### Scenario: 测试使用 simple.ppt
- **WHEN** 测试 PPT Reader 基础解析能力
- **THEN** 使用 `simple.ppt` 静态文件
#### Scenario: 测试使用 multiple_slides.ppt
- **WHEN** 测试 PPT Reader 多幻灯片解析
- **THEN** 使用 `multiple_slides.ppt` 静态文件
#### Scenario: 测试使用 with_images.ppt
- **WHEN** 测试 PPT Reader 图片处理(可选)
- **THEN** 使用 `with_images.ppt` 静态文件

View File

@@ -98,16 +98,6 @@ DEPENDENCIES = {
] ]
} }
}, },
"doc": {
"default": {
"python": None,
"dependencies": [
"markitdown[docx]",
"pypandoc-binary",
"olefile"
]
}
},
"xls": { "xls": {
"default": { "default": {
"python": None, "python": None,
@@ -120,14 +110,5 @@ DEPENDENCIES = {
"olefile" "olefile"
] ]
} }
},
"ppt": {
"default": {
"python": None,
"dependencies": [
"markitdown[pptx]",
"olefile"
]
}
} }
} }

View File

@@ -12,9 +12,7 @@ from readers import (
XlsxReader, XlsxReader,
PptxReader, PptxReader,
HtmlReader, HtmlReader,
DocReader,
XlsReader, XlsReader,
PptReader,
) )
@@ -25,9 +23,7 @@ _READER_KEY_MAP: Dict[Type[BaseReader], str] = {
XlsxReader: "xlsx", XlsxReader: "xlsx",
PptxReader: "pptx", PptxReader: "pptx",
HtmlReader: "html", HtmlReader: "html",
DocReader: "doc",
XlsReader: "xls", XlsReader: "xls",
PptReader: "ppt",
} }

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""文档解析器命令行交互模块,提供命令行接口。支持 DOC、DOCX、XLS、XLSX、PPT、PPTX、PDF、HTML 和 URL。""" """文档解析器命令行交互模块,提供命令行接口。支持 DOCX、XLS、XLSX、PPTX、PDF、HTML 和 URL。"""
import argparse import argparse
import logging import logging
@@ -39,10 +39,10 @@ from readers import READERS
def main() -> None: def main() -> None:
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="DOC、DOCX、XLS、XLSX、PPT、PPTX、PDF、HTML 文件或 URL 解析为 Markdown" description="将 DOCX、XLS、XLSX、PPTX、PDF、HTML 文件或 URL 解析为 Markdown"
) )
parser.add_argument("input_path", help="DOC、DOCX、XLS、XLSX、PPT、PPTX、PDF、HTML 文件或 URL") parser.add_argument("input_path", help="DOCX、XLS、XLSX、PPTX、PDF、HTML 文件或 URL")
parser.add_argument( parser.add_argument(
"-a", "-a",

View File

@@ -6,9 +6,7 @@ from .xlsx import XlsxReader
from .pptx import PptxReader from .pptx import PptxReader
from .pdf import PdfReader from .pdf import PdfReader
from .html import HtmlReader from .html import HtmlReader
from .doc import DocReader
from .xls import XlsReader from .xls import XlsReader
from .ppt import PptReader
READERS = [ READERS = [
DocxReader, DocxReader,
@@ -16,9 +14,7 @@ READERS = [
PptxReader, PptxReader,
PdfReader, PdfReader,
HtmlReader, HtmlReader,
DocReader,
XlsReader, XlsReader,
PptReader,
] ]
__all__ = [ __all__ = [
@@ -28,8 +24,6 @@ __all__ = [
"PptxReader", "PptxReader",
"PdfReader", "PdfReader",
"HtmlReader", "HtmlReader",
"DocReader",
"XlsReader", "XlsReader",
"PptReader",
"READERS", "READERS",
] ]

View File

@@ -1,48 +0,0 @@
"""DOC 文件阅读器,支持多种解析方法。"""
import os
from typing import List, Optional, Tuple
from readers.base import BaseReader
from utils import is_valid_doc
from . import markitdown
from . import pypandoc
PARSERS = [
("MarkItDown", markitdown.parse),
("pypandoc-binary", pypandoc.parse),
]
class DocReader(BaseReader):
"""DOC 文件阅读器"""
def supports(self, file_path: str) -> bool:
return file_path.lower().endswith('.doc')
def parse(self, file_path: str) -> Tuple[Optional[str], List[str]]:
failures = []
# 检查文件是否存在
if not os.path.exists(file_path):
return None, ["文件不存在"]
# 验证文件格式
if not is_valid_doc(file_path):
return None, ["不是有效的 DOC 文件"]
content = None
for parser_name, parser_func in PARSERS:
try:
content, error = parser_func(file_path)
if content is not None:
return content, failures
else:
failures.append(f"- {parser_name}: {error}")
except Exception as e:
failures.append(f"- {parser_name}: [意外异常] {type(e).__name__}: {str(e)}")
return None, failures

View File

@@ -1,10 +0,0 @@
"""使用 MarkItDown 库解析 DOC 文件"""
from typing import Optional, Tuple
from readers._utils import parse_via_markitdown
def parse(file_path: str) -> Tuple[Optional[str], Optional[str]]:
"""使用 MarkItDown 库解析 DOC 文件"""
return parse_via_markitdown(file_path)

View File

@@ -1,29 +0,0 @@
"""使用 pypandoc-binary 库解析 DOC 文件"""
from typing import Optional, Tuple
def parse(file_path: str) -> Tuple[Optional[str], Optional[str]]:
"""使用 pypandoc-binary 库解析 DOC 文件"""
try:
import pypandoc
except ImportError:
return None, "pypandoc-binary 库未安装"
try:
content = pypandoc.convert_file(
source_file=file_path,
to="md",
format="doc",
outputfile=None,
extra_args=["--wrap=none"],
)
except OSError as exc:
return None, f"pypandoc-binary 缺少 Pandoc 可执行文件: {exc}"
except RuntimeError as exc:
return None, f"pypandoc-binary 解析失败: {exc}"
content = content.strip()
if not content:
return None, "文档为空"
return content, None

View File

@@ -1,46 +0,0 @@
"""PPT 文件阅读器,支持多种解析方法。"""
import os
from typing import List, Optional, Tuple
from readers.base import BaseReader
from utils import is_valid_ppt
from . import markitdown
PARSERS = [
("MarkItDown", markitdown.parse),
]
class PptReader(BaseReader):
"""PPT 文件阅读器"""
def supports(self, file_path: str) -> bool:
return file_path.lower().endswith('.ppt')
def parse(self, file_path: str) -> Tuple[Optional[str], List[str]]:
failures = []
# 检查文件是否存在
if not os.path.exists(file_path):
return None, ["文件不存在"]
# 验证文件格式
if not is_valid_ppt(file_path):
return None, ["不是有效的 PPT 文件"]
content = None
for parser_name, parser_func in PARSERS:
try:
content, error = parser_func(file_path)
if content is not None:
return content, failures
else:
failures.append(f"- {parser_name}: {error}")
except Exception as e:
failures.append(f"- {parser_name}: [意外异常] {type(e).__name__}: {str(e)}")
return None, failures

View File

@@ -1,10 +0,0 @@
"""使用 MarkItDown 库解析 PPT 文件"""
from typing import Optional, Tuple
from readers._utils import parse_via_markitdown
def parse(file_path: str) -> Tuple[Optional[str], Optional[str]]:
"""使用 MarkItDown 库解析 PPT 文件"""
return parse_via_markitdown(file_path)

View File

@@ -5,9 +5,7 @@ from .file_detection import (
is_valid_pptx, is_valid_pptx,
is_valid_xlsx, is_valid_xlsx,
is_valid_pdf, is_valid_pdf,
is_valid_doc,
is_valid_xls, is_valid_xls,
is_valid_ppt,
is_html_file, is_html_file,
is_url, is_url,
) )
@@ -17,9 +15,7 @@ __all__ = [
"is_valid_pptx", "is_valid_pptx",
"is_valid_xlsx", "is_valid_xlsx",
"is_valid_pdf", "is_valid_pdf",
"is_valid_doc",
"is_valid_xls", "is_valid_xls",
"is_valid_ppt",
"is_html_file", "is_html_file",
"is_url", "is_url",
] ]

View File

@@ -6,7 +6,7 @@ from typing import List, Optional
def _is_valid_ole(file_path: str) -> bool: def _is_valid_ole(file_path: str) -> bool:
"""验证 OLE2 格式文件(DOC/XLS/PPT""" """验证 OLE2 格式文件(XLS"""
try: try:
import olefile import olefile
except ImportError: except ImportError:
@@ -48,21 +48,11 @@ def is_valid_xlsx(file_path: str) -> bool:
return _is_valid_ooxml(file_path, _XLSX_REQUIRED) return _is_valid_ooxml(file_path, _XLSX_REQUIRED)
def is_valid_doc(file_path: str) -> bool:
"""验证文件是否为有效的 DOC 格式"""
return _is_valid_ole(file_path)
def is_valid_xls(file_path: str) -> bool: def is_valid_xls(file_path: str) -> bool:
"""验证文件是否为有效的 XLS 格式""" """验证文件是否为有效的 XLS 格式"""
return _is_valid_ole(file_path) return _is_valid_ole(file_path)
def is_valid_ppt(file_path: str) -> bool:
"""验证文件是否为有效的 PPT 格式"""
return _is_valid_ole(file_path)
def is_valid_pdf(file_path: str) -> bool: def is_valid_pdf(file_path: str) -> bool:
"""验证文件是否为有效的 PDF 格式""" """验证文件是否为有效的 PDF 格式"""
try: try:
@@ -82,7 +72,3 @@ def is_html_file(file_path: str) -> bool:
def is_url(input_str: str) -> bool: def is_url(input_str: str) -> bool:
"""判断输入是否为 URL""" """判断输入是否为 URL"""
return input_str.startswith("http://") or input_str.startswith("https://") return input_str.startswith("http://") or input_str.startswith("https://")

View File

@@ -38,13 +38,6 @@ class TestCLIAdviceOption:
output = stdout + stderr output = stdout + stderr
assert "无法识别" in output or "错误" in output assert "无法识别" in output or "错误" in output
def test_advice_option_doc(self, cli_runner):
"""测试 --advice 选项对 DOC 文件。"""
stdout, stderr, exit_code = cli_runner(["test.doc", "--advice"])
assert exit_code == 0
assert "文件类型: DOC" in stdout
def test_advice_option_xls(self, cli_runner): def test_advice_option_xls(self, cli_runner):
"""测试 --advice 选项对 XLS 文件。""" """测试 --advice 选项对 XLS 文件。"""
stdout, stderr, exit_code = cli_runner(["test.xls", "--advice"]) stdout, stderr, exit_code = cli_runner(["test.xls", "--advice"])
@@ -52,13 +45,6 @@ class TestCLIAdviceOption:
assert exit_code == 0 assert exit_code == 0
assert "文件类型: XLS" in stdout assert "文件类型: XLS" in stdout
def test_advice_option_ppt(self, cli_runner):
"""测试 --advice 选项对 PPT 文件。"""
stdout, stderr, exit_code = cli_runner(["test.ppt", "--advice"])
assert exit_code == 0
assert "文件类型: PPT" in stdout
class TestCLIDefaultOutput: class TestCLIDefaultOutput:
"""测试 CLI 默认输出功能。""" """测试 CLI 默认输出功能。"""

View File

@@ -1 +0,0 @@
"""测试 DocReader 模块。"""

View File

@@ -1,44 +0,0 @@
"""测试所有 DOC Readers 的一致性。"""
import pytest
from readers.doc import markitdown, pypandoc
class TestDocReadersConsistency:
"""验证所有 DOC Readers 解析同一文件时核心文字内容一致。"""
def test_parsers_importable(self):
"""测试所有 parser 模块可以正确导入。"""
# 验证模块导入成功
assert markitdown is not None
assert pypandoc is not None
assert hasattr(markitdown, 'parse')
assert hasattr(pypandoc, 'parse')
def test_parser_functions_callable(self):
"""测试 parse 函数是可调用的。"""
assert callable(markitdown.parse)
assert callable(pypandoc.parse)
def test_all_readers_parse_same_content(self, simple_doc_path):
"""测试所有 Readers 解析同一文件时核心内容一致。"""
# 收集所有 readers 的解析结果
parsers = [
("markitdown", markitdown.parse),
("pypandoc", pypandoc.parse),
]
successful_results = []
for name, parser in parsers:
content, error = parser(simple_doc_path)
if content is not None and content.strip():
successful_results.append((name, content))
# 至少应该有一个 reader 成功解析,或者都不解析也可以(旧格式兼容性问题)
if len(successful_results) > 0:
# 验证所有成功的 readers 都包含核心内容
core_texts = ["测试文档", "第一段", "第二段"]
for name, content in successful_results:
# 至少包含一个核心文本
assert any(text in content for text in core_texts), \
f"{name} 解析结果不包含核心内容"

View File

@@ -1,49 +0,0 @@
"""测试 MarkItDown DOC Reader 的解析功能。"""
import pytest
import os
from readers.doc import markitdown
class TestMarkitdownDocReaderParse:
"""测试 MarkItDown DOC Reader 的 parse 方法。"""
def test_module_importable(self):
"""测试模块可以正确导入。"""
assert markitdown is not None
assert hasattr(markitdown, 'parse')
assert callable(markitdown.parse)
def test_file_not_exists(self, tmp_path):
"""测试文件不存在的情况。"""
non_existent_file = str(tmp_path / "non_existent.doc")
content, error = markitdown.parse(non_existent_file)
# 验证返回 None 和错误信息
assert content is None
assert error is not None
def test_parse_simple_doc(self, simple_doc_path):
"""测试解析简单 DOC 文件。"""
content, error = markitdown.parse(simple_doc_path)
# 只要不崩溃即可,不强制要求成功解析
if content is not None:
assert len(content.strip()) > 0
def test_parse_with_headings_doc(self, with_headings_doc_path):
"""测试解析带标题的 DOC 文件。"""
content, error = markitdown.parse(with_headings_doc_path)
# 只要不崩溃即可
if content is not None:
assert len(content.strip()) > 0
def test_parse_with_table_doc(self, with_table_doc_path):
"""测试解析带表格的 DOC 文件。"""
content, error = markitdown.parse(with_table_doc_path)
# 只要不崩溃即可
if content is not None:
assert len(content.strip()) > 0

View File

@@ -1,33 +0,0 @@
"""测试 pypandoc DOC Reader 的解析功能。"""
import pytest
import os
from readers.doc import pypandoc
class TestPypandocDocReaderParse:
"""测试 pypandoc DOC Reader 的 parse 方法。"""
def test_module_importable(self):
"""测试模块可以正确导入。"""
assert pypandoc is not None
assert hasattr(pypandoc, 'parse')
assert callable(pypandoc.parse)
def test_file_not_exists(self, tmp_path):
"""测试文件不存在的情况。"""
non_existent_file = str(tmp_path / "non_existent.doc")
content, error = pypandoc.parse(non_existent_file)
# 验证返回 None 和错误信息
assert content is None
assert error is not None
def test_parse_simple_doc(self, simple_doc_path):
"""测试解析简单 DOC 文件。"""
content, error = pypandoc.parse(simple_doc_path)
# pypandoc 可能需要额外依赖,只要不崩溃即可
if content is not None:
assert len(content.strip()) > 0

View File

@@ -1 +0,0 @@
"""测试 PptReader 模块。"""

View File

@@ -1,40 +0,0 @@
"""测试所有 PPT Readers 的一致性。"""
import pytest
from readers.ppt import markitdown
class TestPptReadersConsistency:
"""验证所有 PPT Readers 解析同一文件时核心文字内容一致。"""
def test_parsers_importable(self):
"""测试所有 parser 模块可以正确导入。"""
# 验证模块导入成功
assert markitdown is not None
assert hasattr(markitdown, 'parse')
def test_parser_functions_callable(self):
"""测试 parse 函数是可调用的。"""
assert callable(markitdown.parse)
def test_all_readers_parse_same_content(self, simple_ppt_path):
"""测试所有 Readers 解析同一文件时核心内容一致。"""
# 收集所有 readers 的解析结果
parsers = [
("markitdown", markitdown.parse),
]
successful_results = []
for name, parser in parsers:
content, error = parser(simple_ppt_path)
if content is not None and content.strip():
successful_results.append((name, content))
# 至少应该有一个 reader 成功解析,或者都不解析也可以
if len(successful_results) > 0:
# 验证所有成功的 readers 都包含核心内容
core_texts = ["测试", "演示", "文稿"]
for name, content in successful_results:
# 至少包含一个核心文本
assert any(text in content for text in core_texts), \
f"{name} 解析结果不包含核心内容"

View File

@@ -1,41 +0,0 @@
"""测试 MarkItDown PPT Reader 的解析功能。"""
import pytest
import os
from readers.ppt import markitdown
class TestMarkitdownPptReaderParse:
"""测试 MarkItDown PPT Reader 的 parse 方法。"""
def test_module_importable(self):
"""测试模块可以正确导入。"""
assert markitdown is not None
assert hasattr(markitdown, 'parse')
assert callable(markitdown.parse)
def test_file_not_exists(self, tmp_path):
"""测试文件不存在的情况。"""
non_existent_file = str(tmp_path / "non_existent.ppt")
content, error = markitdown.parse(non_existent_file)
# 验证返回 None 和错误信息
assert content is None
assert error is not None
def test_parse_simple_ppt(self, simple_ppt_path):
"""测试解析简单 PPT 文件。"""
content, error = markitdown.parse(simple_ppt_path)
# 只要不崩溃即可
if content is not None:
assert len(content.strip()) > 0
def test_parse_multiple_slides_ppt(self, multiple_slides_ppt_path):
"""测试解析多幻灯片 PPT 文件。"""
content, error = markitdown.parse(multiple_slides_ppt_path)
# 只要不崩溃即可
if content is not None:
assert len(content.strip()) > 0