Repository navigation
Preserve line breaks and hyphens in Table.to_markdown(clean=True) - #5242
Merged
Merged
Conversation
veget-able
approved these changes
Nov 5, 2026
veget-able
left a comment
Collaborator
There was a problem hiding this comment.
Thanks for the fix. Escaping source text before adding generated markup addresses the line-break and hyphen issues directly.
In my 168-page sample, default Markdown was unchanged across all 421 table outputs from the layout and non-layout runs. With clean=True, generated line breaks and ordinary hyphens are now preserved. Cell extraction and header metadata were unchanged as well.
Looks good to me. One small documentation suggestion: could the clean docstring say that it HTML-escapes source text while preserving generated line breaks and formatting? That would describe the behaviour more accurately than saying Markdown syntax is removed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem and cause
Table.to_markdown(clean=True)escapes markup generated by the exporter itself.This makes real line breaks display as literal
<br>and ordinary hyphens orminus signs display as literal
-. The issue occurs in both headers and body cells.Headers —
Table.to_markdown(),src/table.py:1831–1833:A real newline is first converted to
<br>.html.escape()then turns thatgenerated tag into
<br>, so the renderer displays the tag as text insteadof inserting a line break.
The same expression first converts
-to-, then escapes the entity'sampersand, producing
&#45;. Rendering therefore shows the literal-rather than a hyphen, including in negative numbers.
Body cells —
extract_cells(), line 380, followed byTable.to_markdown(), lines 1851–1852:extract_cells(..., markdown=True)has already inserted<br>between text lines.The later whole-cell call
html.escape(cell.replace("-", "-"))causes thesame two problems. Escaping source text and escaping generated markup have been
combined into one operation.
Fix
<br>.cleanintoextract_cells()and escape source span text before combiningit with generated line breaks and font formatting.
Source strings such as
A<br>BandA-Bstill display literally. Font-derivedformatting and the default
clean=Falseoutput are preserved.Reproduction
The attached
markdown_export_comparison.pdfuses the same row IDs across three pages:\nrepresentsan actual newline.
from the patched library.
clean=Trueresult rendered as Markdown.Compare ID 01 for newlines, ID 02 for hyphens and negative numbers, and the
multiline header. ID 14 is the literal
<br>control that must remain text.Rows 03–10 and the additional header-pipe example illustrate separate Markdown
issues; this patch addresses the newline and hyphen defects.
reproduce_markdown.pygenerates the input PDF, verifies extracted values andprints the exact Markdown returned by the installed PyMuPDF version.
Run from the directory containing the script:
Tests and environment
after it. They cover headers and body cells, newlines, hyphens/negative numbers,
literal tags/entities, font styles, internal/external headers, empty-header names,
merged cells, both
fill_emptysettings and unchangedclean=Falseoutput.tests/test_tables.py: all 46 pass before and after.and Mistune, plus six real tables from three upstream fixtures and three local
manuals. The six-table checks restore line breaks without changing table
geometry, extracted text or default Markdown.
Environment: Python 3.12.2, pytest 7.4.4, saved main Python sources with released
PyMuPDF 2.0 / MuPDF 1.28.5 compiled components. The branch base
16c664fhas thesame Git tree as the tested
773a0d9snapshot. The PDF comparison usesmarkdown-it-py 2.2.0 and Chromium; the regression tests themselves require no
Markdown renderer.
Additional
tests/test_markdown_support.pychecks have the same 2 failures and1 setup error before and after: the local checkout lacks
nur-ruhig.jpgandtest_markdown_bad_unicode.md, and the missing-image warning affects the followingtest's setup.
ATTACHMENT_NOTES.txt
markdown_export_comparison.pdf
reproduce_markdown.py