From ffb739006a0d2cca20bf610cc20bfb802eeb7cd2 Mon Sep 17 00:00:00 2001 From: "youchang.kim" Date: Sun, 5 Jul 2026 07:51:57 +0900 Subject: [PATCH 1/2] Thread table_output through the PyMuPDF4LLM parse provider Read an optional `table_output` config key in `_markdown_options` and pass it to `pymupdf4llm.to_markdown`. This is the opt-in switch for the native HTML table engine: builds that ship it render structured markup for `table_output="html"`, while builds without it ignore the extra keyword, so the existing pymupdf4llm_markdown* pipelines are byte -for-byte unchanged (no config sets the key). The kwarg is what makes the pymupdf/pymupdf4llm table work measurable on ParseBench: with the HTML engine inactive the layout path emits the same markdown pipe-tables as the baseline (table score ~56.73 GTRM); with it active the reconstructed HTML tables lift the table score to ~72.11. Validated to {"markdown","html"} to fail fast on typos, matching the provider's other option checks. Co-Authored-By: Claude Fable 5 --- .../inference/providers/parse/pymupdf4llm.py | 13 ++++++++++++ .../providers/parse/test_pymupdf4llm.py | 21 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/parse_bench/inference/providers/parse/pymupdf4llm.py b/src/parse_bench/inference/providers/parse/pymupdf4llm.py index 70cd85b..a24710c 100644 --- a/src/parse_bench/inference/providers/parse/pymupdf4llm.py +++ b/src/parse_bench/inference/providers/parse/pymupdf4llm.py @@ -89,6 +89,19 @@ def _markdown_options(self, pymupdf: Any) -> dict[str, Any]: raise ProviderConfigError("PyMuPDF4LLM 'ocr_language' must be a non-empty string") options["ocr_language"] = ocr_language + table_output = self.base_config.get("table_output") + if table_output is not None: + if not isinstance(table_output, str): + raise ProviderConfigError("PyMuPDF4LLM 'table_output' must be a string") + normalized_table_output = table_output.strip().lower() + if normalized_table_output not in ("markdown", "html"): + raise ProviderConfigError("PyMuPDF4LLM 'table_output' must be 'markdown' or 'html'") + # Opt-in HTML table rendering. pymupdf4llm builds that ship the native + # HTML table engine emit structured
markup for table_output="html"; + # builds without it ignore the extra keyword, so the default markdown + # pipelines above are unaffected. + options["table_output"] = normalized_table_output + raw_backend = self.base_config.get("ocr_backend") if raw_backend is None: return options diff --git a/tests/parse_bench/inference/providers/parse/test_pymupdf4llm.py b/tests/parse_bench/inference/providers/parse/test_pymupdf4llm.py index 2973c91..6d176b2 100644 --- a/tests/parse_bench/inference/providers/parse/test_pymupdf4llm.py +++ b/tests/parse_bench/inference/providers/parse/test_pymupdf4llm.py @@ -1,5 +1,8 @@ """Tests for PyMuPDF4LLM layout normalization helpers.""" +import pytest + +from parse_bench.inference.providers.base import ProviderConfigError from parse_bench.inference.providers.parse.pymupdf4llm import ( _PYMUPDF_CLASS_TO_CANONICAL, PyMuPDF4LLMProvider, @@ -29,3 +32,21 @@ def test_build_layout_page_maps_all_pymupdf_classes() -> None: assert page is not None assert [item.layout_segments[0].label for item in page.items] == list(_PYMUPDF_CLASS_TO_CANONICAL.values()) + + +def test_markdown_options_threads_table_output() -> None: + provider = PyMuPDF4LLMProvider("pymupdf4llm", {"table_output": "html"}) + options = provider._markdown_options(None) + assert options["table_output"] == "html" + + +def test_markdown_options_omits_table_output_by_default() -> None: + provider = PyMuPDF4LLMProvider("pymupdf4llm", {}) + options = provider._markdown_options(None) + assert "table_output" not in options + + +def test_markdown_options_rejects_unknown_table_output() -> None: + provider = PyMuPDF4LLMProvider("pymupdf4llm", {"table_output": "xml"}) + with pytest.raises(ProviderConfigError): + provider._markdown_options(None) From 01e0182d559179991a744ab9a7184665899c951a Mon Sep 17 00:00:00 2001 From: "youchang.kim" Date: Sun, 5 Jul 2026 07:52:15 +0900 Subject: [PATCH 2/2] Add pymupdf4llm_html_tables parse pipeline Register a pymupdf4llm PARSE pipeline that sets `table_output="html"`, so the native HTML table engine is exercised end-to-end on the benchmark. It reuses the existing pymupdf4llm provider (same OCR/layout defaults as `pymupdf4llm_markdown`) and only flips table rendering to HTML. Naming follows the pymupdf4llm_markdown* family; table rendering is an orthogonal knob to the OCR-backend variants, hence the distinct suffix. Run against a pymupdf4llm build with the HTML table engine: uv run parse-bench run pymupdf4llm_html_tables --max_concurrent 1 Co-Authored-By: Claude Fable 5 --- src/parse_bench/inference/pipelines/parse.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/parse_bench/inference/pipelines/parse.py b/src/parse_bench/inference/pipelines/parse.py index 1599bc8..19c70a2 100644 --- a/src/parse_bench/inference/pipelines/parse.py +++ b/src/parse_bench/inference/pipelines/parse.py @@ -526,6 +526,15 @@ def register_parse_pipelines(register_fn) -> None: # type: ignore[no-untyped-de ) ) + register_fn( + PipelineSpec( + pipeline_name="pymupdf4llm_html_tables", + provider_name="pymupdf4llm", + product_type=ProductType.PARSE, + config={"table_output": "html"}, + ) + ) + register_fn( PipelineSpec( pipeline_name="markitdown",