[Bug report] Table splits fail due to postponed-content height constraint
Yoshua Wakeham via reportlab-users <[email protected]> Thu, 13 Nov 2025 16:44:52 -0500
| Newsgroups | gmane.comp.python.reportlab.user |
|---|---|
| Message-ID | <CAPt=5qSZSsoF_0ux8N1JjG_e9oS6aUxN1v6vgo3D529HZ=wf5w@mail.gmail.com> |
--000000000000267298064380cbe1 Content-Type: multipart/alternative; boundary="000000000000267297064380cbdf" --000000000000267297064380cbdf Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi there, I'd like to draw attention to a bug in within-row table splits. Note: this one was first reported in 2024 by Christian Zwicknagl in the Google mirror of this mailing list (link <https://groups.google.com/g/reportlab-users/c/NhklESoh3mg/m/pO8Ve7VlCgAJ>)= . It seems that the report didn't get noticed, because it was only ever posted to the mirror. I have adapted his test code and patch, but I don't have his contact details so I haven't been able to communicate with him to see if he would still be interested in a fix. (Christian, if you're out there, thank you for reporting this in 2024!) At present, table row splits will fail if the height of the "postponed" content exceeds the height of the original row, minus the space available for the "non-postponed" content. The problem is that this constraint seems to cause perfectly-valid splits to fail =E2=80=93 and doesn't (as far as I = can see) prevent any specific *invalid* split case. While at first blush it might seem that the sum of the parts of a split row should always equal the height of the original row, in fact splitting cells usually introduces some amount of additional padding/space which "inflates" the height of the row. As Christian reported, it seems that cells containing many flowables can trigger this split failure fairly easily. I've attached a very small example that demonstrates the problem, by splitting a cell containing just 38 small paragraphs. When run against reportlab v4.4.4, it fails with a layout error: reportlab.platypus.doctemplate.LayoutError: Flowable <Table@0x1067B9450 1 rows x 1 cols(tallest row 702)> with cell(0,0) containing '<Paragraph at 0x1067bebd0>'(200 x 702), tallest cell 702.0 points, too large on page 2 in frame 'normal'(439.27559055118115 x 685.8897637795277*) of template 'Later' I've attached a patch, adapted from Christian's similar patch, that removes the height constraint on postponed content =E2=80=93 rather, if we attempt = to split a flowable in the cell, then provided that *some* flowable fits in the first half of the split, we simply postpone everything else. I've confirmed that with this patch, the example code succeeds. I've also confirmed that all existing tests pass with this change applied. Best regards, Yosh --=20 *Yoshua Wakeham* Senior Software Developer [email protected] --000000000000267297064380cbdf Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div>Hi there,</div><div><br></div><div>I'd like to dr= aw attention to a bug in within-row table splits.</div><div><br></div><div>= Note: this one was first reported in 2024 by=C2=A0Christian Zwicknagl in th= e Google mirror of this mailing=C2=A0list (<a href=3D"https://groups.google= .com/g/reportlab-users/c/NhklESoh3mg/m/pO8Ve7VlCgAJ">link</a>). It seems th= at the report didn't=C2=A0get noticed, because it was only ever posted = to the mirror. I have adapted his test code and patch, but I don't have= his contact details so I haven't been able to communicate=C2=A0with hi= m to see if he would still be interested in a fix. (Christian, if you'r= e out there, thank you for reporting this in 2024!)</div><div><br></div><di= v>At present, table row splits will fail if the height of the "postpon= ed" content exceeds the height of the original row, minus the space av= ailable for the "non-postponed" content. The problem is that this= constraint seems to cause perfectly-valid splits to fail =E2=80=93 and doe= sn't (as far as I can see) prevent any specific <i>invalid</i>=C2=A0spl= it case.</div><div><br></div><div>While at first blush it might seem that t= he sum of the parts of a split row should always equal the height of the or= iginal row, in fact splitting cells usually introduces some amount of addit= ional padding/space which "inflates" the height of the row. As Ch= ristian reported, it=C2=A0seems that cells=C2=A0containing=C2=A0many flowab= les can=C2=A0trigger=C2=A0this split failure fairly easily.</div><div><br><= /div><div>I've attached a very small example that demonstrates the prob= lem,=C2=A0by splitting a cell containing just 38 small paragraphs. When run= against reportlab v4.4.4, it fails with a layout error:</div><div><br></di= v><blockquote style=3D"margin:0 0 0 40px;border:none;padding:0px"><div>repo= rtlab.platypus.doctemplate.LayoutError: Flowable <Table@0x1067B9450 1 ro= ws x 1 cols(tallest row 702)> with cell(0,0) containing</div><div>'&= lt;Paragraph at 0x1067bebd0>'(200 x 702), tallest cell 702.0 points,= =C2=A0too large on page 2 in frame 'normal'(439.27559055118115 x 6= 85.8897637795277*) of template 'Later'</div></blockquote><div><br><= /div>I've attached a patch, adapted from Christian's similar patch,= that removes the height constraint on postponed content =E2=80=93 rather, = if we attempt to split a flowable in the cell, then provided that <i>some</= i> flowable fits in the first half of the split, we simply postpone everyth= ing else.<div><br></div><div>I've confirmed that with this patch, the e= xample code succeeds. I've also confirmed that all existing tests pass = with this change applied.</div><div><br></div><div>Best regards,</div><div>= Yosh</div><div><div><br></div><span class=3D"gmail_signature_prefix">-- </s= pan><br><div dir=3D"ltr" class=3D"gmail_signature" data-smartmail=3D"gmail_= signature"><div dir=3D"ltr"><b style=3D"color:rgb(34,34,34)">Yoshua Wakeham= <br></b><br style=3D"color:rgb(34,34,34)"><span style=3D"color:rgb(34,34,34= )">Senior Software Developer</span><br style=3D"color:rgb(34,34,34)"><span = style=3D"color:rgb(34,34,34)">[email protected]</span><br></div></div></div= ></div> --000000000000267297064380cbdf-- --000000000000267298064380cbe1 Content-Type: text/x-python-script; charset="US-ASCII"; name="repro_split_postponed_content_height_bug.py" Content-Disposition: attachment; filename="repro_split_postponed_content_height_bug.py" Content-Transfer-Encoding: base64 Content-ID: <f_mhxyctym0> X-Attachment-Id: f_mhxyctym0 ZnJvbSByZXBvcnRsYWIucGxhdHlwdXMgaW1wb3J0ICgKICAgIFBhcmFncmFwaCwKICAgIFRhYmxl LAopCmZyb20gcmVwb3J0bGFiLnBsYXR5cHVzLmRvY3RlbXBsYXRlIGltcG9ydCBTaW1wbGVEb2NU ZW1wbGF0ZQoKZGF0YSA9IFsoW1BhcmFncmFwaChmIih7eH0pIiArICIgVGhpcyBpcyBhIHNtYWxs IHBhcmFwcmFwaC4iICogNCkgZm9yIHggaW4gcmFuZ2UoMzgpXSwpXQpjb2xXaWR0aHMgPSAyMDAK CnQgPSBUYWJsZSgKICAgIGRhdGEsCiAgICBjb2xXaWR0aHM9Y29sV2lkdGhzLAogICAgc3BsaXRJ blJvdz0xLAopCgpTaW1wbGVEb2NUZW1wbGF0ZSgib3V0cHV0LnBkZiIsIHNob3dCb3VuZGFyeT0x KS5idWlsZChbdF0pCg== --000000000000267298064380cbe1 Content-Type: application/octet-stream; name="0001-remove-height-constraint-on-postponed-content.patch" Content-Disposition: attachment; filename="0001-remove-height-constraint-on-postponed-content.patch" Content-Transfer-Encoding: base64 Content-ID: <f_mhxyd1et1> X-Attachment-Id: f_mhxyd1et1 RnJvbSA4Yjk1NmE2NDc3NmVmZTFmZGM0NmRkMDg5MjVjZDM5MjliNTkxMTA5IE1vbiBTZXAgMTcg MDA6MDA6MDAgMjAwMQpGcm9tOiBZb3NodWEgV2FrZWhhbSA8eW9zaEBhdHRpY3VzLnRlY2g+CkRh dGU6IFRodSwgMTMgTm92IDIwMjUgMTY6Mzc6MDggLTA1MDAKU3ViamVjdDogW1BBVENIXSByZW1v dmUgaGVpZ2h0IGNvbnN0cmFpbnQgb24gcG9zdHBvbmVkIGNvbnRlbnQKCi0tLQogc3JjL3JlcG9y dGxhYi9wbGF0eXB1cy90YWJsZXMucHkgfCAzOCArKysrKysrKysrKystLS0tLS0tLS0tLS0tLS0t LS0tLQogMSBmaWxlIGNoYW5nZWQsIDE0IGluc2VydGlvbnMoKyksIDI0IGRlbGV0aW9ucygtKQoK ZGlmZiAtLWdpdCBhL3NyYy9yZXBvcnRsYWIvcGxhdHlwdXMvdGFibGVzLnB5IGIvc3JjL3JlcG9y dGxhYi9wbGF0eXB1cy90YWJsZXMucHkKaW5kZXggMWJjNTA5MGYuLjQ3ZTQyMWUzIDEwMDc1NQot LS0gYS9zcmMvcmVwb3J0bGFiL3BsYXR5cHVzL3RhYmxlcy5weQorKysgYi9zcmMvcmVwb3J0bGFi L3BsYXR5cHVzL3RhYmxlcy5weQpAQCAtMTQ2MCw3ICsxNDYwLDcgQEAgb25seSByb3dzIG1heSBi ZSBzdHJpbmdzIHdpdGggdmFsdWVzIGluIHtfU1BFQ0lBTFJPV1Mhcn0nJycpCiAgICAgICAgIGlm IGlzaW5zdGFuY2UodmFsdWUsICh0dXBsZSwgbGlzdCkpOgogICAgICAgICAgICAgbmV3Q2VsbENv bnRlbnQgPSBbXQogICAgICAgICAgICAgcG9zdHBvbmVkQ29udGVudCA9IFtdCi0gICAgICAgICAg ICBzcGxpdCA9IEZhbHNlCisgICAgICAgICAgICBmbG93YWJsZV9zcGxpdF9hdHRlbXB0ZWQgPSBG YWxzZQogICAgICAgICAgICAgRkggPSBbXQogICAgICAgICAgICAgY2VsbEhlaWdodCA9IHNlbGYu X2xpc3RDZWxsR2VvbSh2YWx1ZSwgd2lkdGgsIHN0eWxlLEg9RkgpWzFdCiAKQEAgLTE0NzEsMjAg KzE0NzEsMTcgQEAgb25seSByb3dzIG1heSBiZSBzdHJpbmdzIHdpdGggdmFsdWVzIGluIHtfU1BF Q0lBTFJPV1Mhcn0nJycpCiAKICAgICAgICAgICAgIGZvciBmbG93YWJsZSxfZmggaW4gemlwKHZh bHVlLEZIKToKICAgICAgICAgICAgICAgICBmbG93YWJsZV9oZWlnaHQgPSBnZXRhdHRyKGZsb3dh YmxlLCdoZWlnaHQnLF9maCkKLSAgICAgICAgICAgICAgICBpZiBzcGxpdDoKLSAgICAgICAgICAg ICAgICAgICAgaWYgZmxvd2FibGVfaGVpZ2h0IDw9IGhlaWdodDE6Ci0gICAgICAgICAgICAgICAg ICAgICAgICBwb3N0cG9uZWRDb250ZW50LmFwcGVuZChmbG93YWJsZSkKLSAgICAgICAgICAgICAg ICAgICAgICAgICMgU2hyaW5rIHRoZSBhdmFpbGFibGUgaGVpZ2h0OgotICAgICAgICAgICAgICAg ICAgICAgICAgaGVpZ2h0MSAtPSBmbG93YWJsZV9oZWlnaHQKLSAgICAgICAgICAgICAgICAgICAg ZWxzZToKLSAgICAgICAgICAgICAgICAgICAgICAgICMgVGhlIGNvbnRlbnQgZG9lc24ndCBmaXQg YWZ0ZXIgdGhlIHNwbGl0OgotICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtdCisgICAg ICAgICAgICAgICAgaWYgZmxvd2FibGVfc3BsaXRfYXR0ZW1wdGVkOgorICAgICAgICAgICAgICAg ICAgICAjIHRoZSBmbG93YWJsZSBzcGxpdCBtYXkgaGF2ZSBmYWlsZWQsIGJ1dCB3ZSBtYWRlIHNv bWUgcHJvZ3Jlc3MsCisgICAgICAgICAgICAgICAgICAgICMgc28gcG9zdHBvbmUgZXZlcnl0aGlu ZyBlbHNlIGFuZCBob3BlIGl0IGNhbiBiZSBzcGxpdC93cmFwcGVkIGxhdGVyIG9uCisgICAgICAg ICAgICAgICAgICAgIHBvc3Rwb25lZENvbnRlbnQuYXBwZW5kKGZsb3dhYmxlKQogICAgICAgICAg ICAgICAgIGVsaWYgdXNlZEhlaWdodCArIGZsb3dhYmxlX2hlaWdodCArIGZsb3dhYmxlLmdldFNw YWNlQmVmb3JlKCkgPD0gaGVpZ2h0MDoKICAgICAgICAgICAgICAgICAgICAgbmV3Q2VsbENvbnRl bnQuYXBwZW5kKGZsb3dhYmxlKQogICAgICAgICAgICAgICAgICAgICB1c2VkSGVpZ2h0ICs9IGZs b3dhYmxlX2hlaWdodCArIGZsb3dhYmxlLmdldFNwYWNlQmVmb3JlKCkgKyBmbG93YWJsZS5nZXRT cGFjZUFmdGVyKCkKICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAj IFRoaXMgaXMgd2hlcmUgd2UgbmVlZCB0byBzcGxpdAogICAgICAgICAgICAgICAgICAgICBzcGxp dEhlaWdodCA9IGhlaWdodDAtdXNlZEhlaWdodC1mbG93YWJsZS5nZXRTcGFjZUJlZm9yZSgpCisg ICAgICAgICAgICAgICAgICAgIHNwbGl0cyA9IE5vbmUKICAgICAgICAgICAgICAgICAgICAgaWYg aGFzYXR0cihmbG93YWJsZSwnX2ZpbmRTcGxpdCcpOgogICAgICAgICAgICAgICAgICAgICAgICAg X3csX0gsIFMwLCBTMSA9IGZsb3dhYmxlLl9maW5kU3BsaXQoZ2V0YXR0cihzZWxmLCdjYW52JyxO b25lKSx3aWR0aCxzcGxpdEhlaWdodCxtZXJnZVNwYWNlPTEsb2JqPU5vbmUsY29udGVudD1Ob25l LHBhcmFGaXg9VHJ1ZSkKICAgICAgICAgICAgICAgICAgICAgICAgIGlmIFMwIGFuZCBTMToKQEAg LTE0OTcsMjMgKzE0OTQsMTYgQEAgb25seSByb3dzIG1heSBiZSBzdHJpbmdzIHdpdGggdmFsdWVz IGluIHtfU1BFQ0lBTFJPV1Mhcn0nJycpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3 Q2VsbENvbnRlbnQuYXBwZW5kKHNwbGl0c1swXSkKICAgICAgICAgICAgICAgICAgICAgICAgICAg ICBwb3N0cG9uZWRDb250ZW50LmFwcGVuZChzcGxpdHNbMV0pCiAgICAgICAgICAgICAgICAgICAg IGlmIG5vdCBzcGxpdHM6Ci0gICAgICAgICAgICAgICAgICAgICAgICAjIFdlIGNvdWxkbid0IHNw bGl0IHRoaXMgZmxvd2FibGUgYXQgdGhlIGRlc2lyZWQKLSAgICAgICAgICAgICAgICAgICAgICAg ICMgcG9pbnQuIElmIHdlIGFscmVhZHkgaGFzIGFkZGVkIHByZXZpb3VzIHBhcmFncmFwaHMKLSAg ICAgICAgICAgICAgICAgICAgICAgICMgdG8gdGhlIGNvbnRlbnQsIGp1c3QgYWRkIGV2ZXJ5dGhp bmcgYWZ0ZXIgdGhlIHNwbGl0LgotICAgICAgICAgICAgICAgICAgICAgICAgIyBBbHNvIHRyeSBh ZGRpbmcgaXQgYWZ0ZXIgdGhlIHNwbGl0IGlmIHZhbGlnbiBpc24ndCBUT1AKLSAgICAgICAgICAg ICAgICAgICAgICAgIGlmIG5ld0NlbGxDb250ZW50IG9yIHN0eWxlLnZhbGlnbiAhPSAiVE9QIjoK LSAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBmbG93YWJsZV9oZWlnaHQgPD0gaGVpZ2h0 MToKLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdHBvbmVkQ29udGVudC5hcHBl bmQoZmxvd2FibGUpCi0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU2hyaW5rIHRo ZSBhdmFpbGFibGUgaGVpZ2h0OgotICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWln aHQxIC09IGZsb3dhYmxlX2hlaWdodAotICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2U6 Ci0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVGhlIGNvbnRlbnQgZG9lc24ndCBm aXQgYWZ0ZXIgdGhlIHNwbGl0OgotICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1 cm4gW10KLSAgICAgICAgICAgICAgICAgICAgICAgIGVsc2U6Ci0gICAgICAgICAgICAgICAgICAg ICAgICAgICAgIyBXZSBjb3VsZCBub3Qgc3BsaXQgdGhpcywgc28gd2UgZmFpbDoKKyAgICAgICAg ICAgICAgICAgICAgICAgICMgV2UgY291bGRuJ3Qgc3BsaXQgdGhpcyBmbG93YWJsZSBhdCB0aGUg ZGVzaXJlZCBwb2ludAorICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5vdCBuZXdDZWxsQ29u dGVudCkgYW5kIHN0eWxlLnZhbGlnbiA9PSAiVE9QIjoKKyAgICAgICAgICAgICAgICAgICAgICAg ICAgICAjIFRoaXMgaXMgdGhlIGZpcnN0IGZsb3dhYmxlIGluIHRoZSBjZWxsLCBhbmQgdGhlIGNl bGwKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGlzIHRvcC1hbGlnbmVkIC0gc2luY2Ug c3BsaXR0aW5nIHRoZSBmbG93YWJsZSBmYWlsZWQsCisgICAgICAgICAgICAgICAgICAgICAgICAg ICAgIyBzcGxpdHRpbmcgdGhlIGNlbGwgaGFzIGZhaWxlZC4KICAgICAgICAgICAgICAgICAgICAg ICAgICAgICByZXR1cm4gW10KIAotICAgICAgICAgICAgICAgICAgICBzcGxpdCA9IFRydWUKKyAg ICAgICAgICAgICAgICAgICAgICAgICMgcG9zdHBvbmUgdGhpcyBmbG93YWJsZSwgYW5kIGhvcGUg d2UgY2FuIHdyYXAvc3BsaXQgbGF0ZXIKKyAgICAgICAgICAgICAgICAgICAgICAgIHBvc3Rwb25l ZENvbnRlbnQuYXBwZW5kKGZsb3dhYmxlKQorICAgICAgICAgICAgICAgICAgICBmbG93YWJsZV9z cGxpdF9hdHRlbXB0ZWQgPSBUcnVlCiAKICAgICAgICAgICAgIHJldHVybiAodHVwbGUobmV3Q2Vs bENvbnRlbnQpLCB0dXBsZShwb3N0cG9uZWRDb250ZW50KSkKIAotLSAKMi4zOS4xCgo= --000000000000267298064380cbe1 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline