Skip to content

feat: add bounded XLSX to Markdown parsing - #8

Merged
caichuanwang merged 12 commits into
masterfrom
feat/xlsx-parsing
Aug 17, 2026
Merged

caichuanwang merged 12 commits into
masterfrom
feat/xlsx-parsing

Conversation

@caichuanwang

Copy link
Copy Markdown
Owner

Summary

OpenDocs 现在可以将标准 .xlsx 工作簿解析为确定性的 Markdown。解析支持 path、bytes 和 binary stream,并保持 parse() 与 aparse() 的结果、warning 顺序和错误类型一致。

本 PR 完成 v0.2.0 XLSX 计划的实现:

  • 识别并安全预检 XLSX 容器、OOXML 关系和资源预算。
  • 保留全部工作表及 Visible、Hidden、Very Hidden 状态,支持空表、合并区域、表格和稀疏区域。
  • 保留保存的显示值、公式缓存回退、货币、百分比、日期时间、会计格式和常见自定义格式。
  • 提取批注、文本框、页眉页脚、超链接文字、图表标题/分类/系列/数值及图片媒体。
  • 图表和图片采用原生数据优先、视觉增强可失败的策略;视觉失败不会阻断原生结果。
  • 外部 URL、外部工作簿和数据连接只保留引用,不发起网络访问。
  • 发布检查覆盖 XLSX parser 模块、依赖、构建产物和隔离 wheel smoke。

Design decisions

  • 结果继续保持 Markdown 字符串,不新增公共返回类型。
  • XLSX 工作表不映射为 page,因此 max_pages 不限制 sheet 数量。
  • 不支持 .xls、.xlsm、.xlsb,不重算公式,不还原字体、颜色和像素级布局。
  • 真实 XLSX 工作簿和 live vision provider 当前没有可用样本,发布计划将其标记为 not_run。

Validation

  • uv run --frozen pytest tests/test_markdown.py tests/test_api_xlsx.py tests/test_xlsx_*.py -q -> 163 passed
  • uv run --frozen pytest -q -> 818 passed, 9 skipped(在最后一轮边界修复前)
  • uv run --frozen ruff check .
  • uv run --frozen ruff format --check .
  • uv run --frozen ty check src tests
  • git diff --check
  • uv build、artifact checker、隔离 wheel smoke 已通过

Follow-up evidence

  • 维护者提供真实工作簿后,需要进行私有人工对照验收。
  • GitHub Actions 的 Python 3.11/3.12/3.13 发布矩阵已配置,但未在本地模拟 GitHub runner。

先锁定 XLSX 的容器身份、包关系安全和默认 registry seam,为后续原生内容解析提供有界入口。

Constraint: 关系 XML 使用 defusedxml;不改变 DOCX/PPTX 包预算与公共 Markdown 返回契约。

Tested: 154 focused tests;Ruff check/format;ty check src tests;uv sync --all-groups --frozen;git diff --check。
为 sheet-oriented 严格 wire 建模,并在 openpyxl 介入前完成 OOXML 关系、XML 安全和可放大集合的资源预检。

Constraint: 保持公共 Markdown API 与 8 MiB inline / 12 MiB frame 契约,不引入 page 语义。

Rejected: 依赖 full-mode loader 边加载边发现超限。

Confidence: high

Scope-risk: 真实 full-mode 峰值 RSS 仍需 U7 资源特征验证。

Tested: uv run --frozen pytest tests/test_xlsx_models.py tests/test_xlsx_preflight.py tests/test_runtime.py tests/test_models.py tests/test_detection.py tests/test_registry.py tests/test_office_package.py -q

Tested: uv run --frozen ruff check .

Tested: uv run --frozen ruff format --check .

Tested: uv run --frozen ty check src tests

Not-tested: 完整 public suite、真实 XLSX、私有 corpus、build
在安全预检后单次加载工作簿,用 OOXML sidecar 保留公式缓存与回退,并按源顺序生成表格、区域和合并跨度。

Constraint: 不计算公式、不下载外部引用、不把字体颜色或页面语义写入结果。

Rejected: 通过 data_only 双加载或首行猜测表头。

Confidence: high

Scope-risk: 真实工作簿兼容与 full-mode RSS 仍待 U7 私有/资源门验证。

Tested: uv run --frozen pytest tests/test_xlsx_values.py tests/test_xlsx_extract.py tests/test_xlsx_models.py tests/test_xlsx_preflight.py tests/test_office_package.py tests/test_runtime.py -q

Tested: uv run --frozen ruff check .

Tested: uv run --frozen ruff format --check .

Tested: uv run --frozen ty check src tests

Not-tested: 完整 public suite、build、真实 XLSX、私有 corpus
从安全 OOXML 读取批注、threaded comment、文本框、链接和页眉页脚,并把外部引用与不支持对象转成可定位降级。

Constraint: URL 只保留引用且零网络访问;所有对象保持 sheet/A1/ordinal 的稳定顺序。

Rejected: 依赖 openpyxl 不完整的 drawing/comment 映射或静默跳过扩展对象。

Confidence: high

Scope-risk: 真实 threaded-comments 文件仍待私有 corpus 验证。

Tested: uv run --frozen pytest tests/test_xlsx_models.py tests/test_xlsx_values.py tests/test_xlsx_extract.py tests/test_xlsx_preflight.py tests/test_office_package.py tests/test_runtime.py -q

Tested: uv run --frozen ruff check .

Tested: uv run --frozen ruff format --check .

Tested: uv run --frozen ty check src tests

Not-tested: U8 文档/依赖白名单修复前全套仍有 3 个已知发布契约失败;真实 XLSX、私有 corpus
Constraint: 图表数值以 OOXML 原生事实为准,视觉只补充趋势、标注和含义。

Rejected: 不使用 openpyxl 私有图表对象,也不把语义卡冒充 Excel 原始外观。

Confidence: high

Scope-risk: 视觉调度、结果合并与公共 API 由后续编排单元完成。

Tested: 189 focused tests; ruff; format; ty; diff-check.

Not-tested: real XLSX workbooks or live vision providers.
Constraint: 原生事实始终优先,视觉结果只按对象位置追加;模型类失败不得中断 XLSX 文档。

Rejected: 不复用 Office 的致命视觉异常策略,也不把 sheet 映射为 page。

Confidence: high

Scope-risk: 公共输入对等、资源实测和发布 smoke 留给后续单元。

Tested: 279 focused tests; ruff; format; ty; diff-check.

Not-tested: real XLSX workbooks or live vision providers.
Constraint: path、bytes、命名与匿名流在同步和异步 API 下必须走同一 Markdown 与错误契约。

Rejected: 不依赖临时文件扩展名驱动 openpyxl,也不把本机 RSS 测量写成硬保证。

Confidence: high

Scope-risk: 发布文档与构建产物依赖白名单由 U8 收口。

Tested: 136 XLSX tests; 12 lifecycle/API tests; full suite 812 passed, 9 skipped, 3 known U8 failures; ruff; format; ty; diff-check.

Not-tested: real XLSX workbooks, live vision providers, or cross-platform RSS.
Constraint: 当前开发版本保持 0.1.0,v0.2.0 由未来 tag 与证据提交完成切版;真实工作簿门保持 not_run。

Rejected: 不扩大 PR CI 矩阵,不伪造真实样本验收,也不把语义图表预览描述为 Excel 像素还原。

Confidence: high

Scope-risk: live vision、真实 XLSX 与 GitHub-hosted release matrix 尚未运行。

Tested: 817 passed, 9 skipped; uv sync; uv build; artifact checker; isolated wheel smoke; ruff; format; ty; diff-check.

Not-tested: private real XLSX corpus, live provider, or hosted release workflow.
Constraint: 图表本地引用不得超过既有缓存点预算,条件格式仍需保持格式回退语义。

Rejected: 为每个单元格线性扫描全部条件格式区域。

Confidence: high

Scope-risk: XLSX 原生提取的内部资源边界。

Tested: uv run --frozen pytest tests/test_xlsx_*.py tests/test_api_xlsx.py -q; uv run --frozen pytest -q; Ruff; format check; Ty; diff check
Constraint: 原生图表事实、显示格式和外部链接降级必须保持确定性。

Rejected: 将低频格式和图表边界静默丢弃或升级为运行时错误。

Confidence: high

Scope-risk: XLSX 媒体、文本对象和数值格式化。

Tested: 55 focused tests; Ruff; Ty; diff-check
Constraint: XLSX 原生文本进入 Markdown 时不得形成活动 HTML。

Rejected: 仅依赖下游 Markdown 消费者自行禁用原始 HTML。

Confidence: high

Scope-risk: 共享 Markdown pipe-table renderer。

Tested: 75 focused tests; Ruff; Ty; diff-check
Constraint: 常见货币与会计显示语义必须保留。

Confidence: high

Tested: tests/test_xlsx_values.py; Ruff; diff-check
@caichuanwang
caichuanwang merged commit 5702cdc into master Aug 17, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant