Re: Error in table column sizing with Platypus

Robin Becker <[email protected]> Sun, 21 Dec 2025 10:59:49 +0000
Newsgroups gmane.comp.python.reportlab.user
Message-ID <CAOBYczroz1LwgJ60AS=FrT5dzEKiUshXqwvm95r+rBcpYQB5AA@mail.gmail.com>
--===============6012344371152731635==
Content-Type: multipart/alternative; boundary="0000000000003c6eae06467436c6"

--0000000000003c6eae06467436c6
Content-Type: text/plain; charset="UTF-8"

Hi Andy, thanks for the report. It is a bug so perhaps this is a rare case
as tests did not catch it.

I have added a fix and another test. They will be in the release.

On Sat, 20 Dec 2025 at 16:52, Andy Hagar <[email protected]> wrote:

> Hello!
>
> I recently ran into an issue with table column sizing. Initially, the
> error message was for:
> AttributeError: 'float' object has no attribute 'endswith'
>
> An example setup is below to show the error happening.
>
> To get to this code path, I happened to have the following in my table
> using Platypus
> -At least 1 entry in a row uses Paragraph for formatting
> -Specifying colWidth with one entry using percentage "%"
> -Data in columns causing total column width to exceed availableWidth
>
> The error occurs at line 940 in tables.py:
> if w.endswith('%'):
>
> Watching at execution, w is indeed a float.
> Just changing to using the already existing _endswidth(w,'%') function
> does allow the pdf to build, but it is ignoring the "X%" specified.
>
> Changing line 940 and the following has it look at W where the actual "X%"
> value exists, but also changes the calculation on line 941 to handle the
> percentage calc (assuming it is meant to be a % out of 100).
>
> Current:
> if w.endswith('%'):
> W[colNo] = w = availWidth*float(w[:-1])/percentTotal
>
> Updated:
> if _endswith(W[colNo], '%'):
> W[colNo] = w = availWidth * float(W[colNo][:-1]) / 100
>
>
> This change works fine to a point. When you specify a large-ish % and have
> columns that are "wide", other errors start showing up. For the below
> script, 88 or higher % causes errors elsewhere.
>
> This error is already called out in
> https://groups.google.com/g/reportlab-users/c/k7GS01u3jrU
> Error:
> TypeError: '>' not supported between instances of 'NoneType' and 'int'
>
> Caused by Line 440:
> tallest = '(tallest row %d)' % int(max(rh))
>
> Changing to:
> tallest = '(tallest row %d)' % int(max([i for i in rh if i], default=0))
>
> Next error:
> ValueError: <Table@0x20017F3A270 2 rows x 3 cols(tallest row 18)> with
> cell(0,0) containing
> 'Header 1': flowable given negative availWidth=-0.779770753733942 ==
> width=11.220229246266058 - leftPadding=6 - rightPadding=6
>
>
> At this point, as I was changing the % for testing and errors started
> getting out of my depth, I just said "don't use silly %" and went about my
> business :)
>
> ---
>
> Example script to hit this code path:
>
> from reportlab.platypus import SimpleDocTemplate, Table, Paragraph
> from reportlab.lib.pagesizes import letter
> from reportlab.lib.styles import getSampleStyleSheet
>
> styles = getSampleStyleSheet()
>
> data = [
>     ['Header 1', 'Header 2', 'Header 3'],
>     [Paragraph('Row 1, Col 1 wide data wide data wide data wide data',
> styles['Normal']), 'Row 1, Col 2 wide data wide data wide data', 'Row 1,
> Col 3 wide data wide data wide data']
> ]
>
> doc = SimpleDocTemplate("table_endswidth.pdf", pagesize=letter)
> story = []
>
> colwidths = [None, "20%", None]
> table = Table(data, colWidths=colwidths)
>
> story.append(table)
> doc.build(story)
>


-- 
Robin Becker

--0000000000003c6eae06467436c6
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Hi Andy, thanks for the report. It is a bug so perhap=
s this is a rare case as tests did not catch it.</div><div><br></div><div>I=
 have added a fix and another test. They will be in the release.</div></div=
><br><div class=3D"gmail_quote gmail_quote_container"><div dir=3D"ltr" clas=
s=3D"gmail_attr">On Sat, 20 Dec 2025 at 16:52, Andy Hagar &lt;<a href=3D"ma=
ilto:[email protected]">[email protected]</a>&gt; wrote:<br></div><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:=
1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr">Hello!<br><br=
>I recently ran into an issue with table column sizing. Initially, the erro=
r message was for:<br>AttributeError: &#39;float&#39; object has no attribu=
te &#39;endswith&#39;<br><br>An example setup is below to show the error ha=
ppening.<br><br>To get to this code path, I happened to have the following =
in my table using Platypus<br>-At least 1 entry in a row uses Paragraph for=
 formatting<br>-Specifying colWidth with one entry using percentage &quot;%=
&quot;<br>-Data in columns causing total column width to exceed availableWi=
dth<br><br>The error occurs at line 940 in tables.py:<br>if w.endswith(&#39=
;%&#39;):<br><br>Watching at execution, w is indeed a float.<br>Just changi=
ng to using the already existing _endswidth(w,&#39;%&#39;) function does al=
low the pdf to build, but it is ignoring the &quot;X%&quot; specified.<br><=
br>Changing line 940 and the following has it look at W where the actual &q=
uot;X%&quot; value exists, but also changes the calculation on line 941 to =
handle the percentage calc (assuming it is meant to be a % out of 100).<br>=
<br>Current:<br>if w.endswith(&#39;%&#39;):<br>	W[colNo] =3D w =3D availWid=
th*float(w[:-1])/percentTotal<br><br>Updated:<br>if _endswith(W[colNo], &#3=
9;%&#39;):<br>	W[colNo] =3D w =3D availWidth * float(W[colNo][:-1]) / 100<b=
r><br><br>This change works fine to a point. When you specify a large-ish %=
 and have columns that are &quot;wide&quot;, other errors start showing up.=
 For the below script, 88 or higher % causes errors elsewhere.<br><br>This =
error is already called out in <a href=3D"https://groups.google.com/g/repor=
tlab-users/c/k7GS01u3jrU" target=3D"_blank">https://groups.google.com/g/rep=
ortlab-users/c/k7GS01u3jrU</a><br>Error:<br>TypeError: &#39;&gt;&#39; not s=
upported between instances of &#39;NoneType&#39; and &#39;int&#39;<br><br>C=
aused by Line 440:<br>tallest =3D &#39;(tallest row %d)&#39; % int(max(rh))=
<br><br>Changing to:<br>tallest =3D &#39;(tallest row %d)&#39; % int(max([i=
 for i in rh if i], default=3D0))<br><br>Next error:<br>ValueError: &lt;Tab=
le@0x20017F3A270 2 rows x 3 cols(tallest row 18)&gt; with cell(0,0) contain=
ing<br>&#39;Header 1&#39;: flowable given negative availWidth=3D-0.77977075=
3733942 =3D=3D width=3D11.220229246266058 - leftPadding=3D6 - rightPadding=
=3D6<br><br><br>At this point, as I was changing the % for testing and erro=
rs started getting out of my depth, I just said &quot;don&#39;t use silly %=
&quot; and went about my business :)=C2=A0<br><br>---<br><br>Example script=
 to hit this code path:<br><br>from reportlab.platypus import SimpleDocTemp=
late, Table, Paragraph<br>from reportlab.lib.pagesizes import letter<br>fro=
m reportlab.lib.styles import getSampleStyleSheet<br><br>styles =3D getSamp=
leStyleSheet()<br><br>data =3D [<br>=C2=A0 =C2=A0 [&#39;Header 1&#39;, &#39=
;Header 2&#39;, &#39;Header 3&#39;],<br>=C2=A0 =C2=A0 [Paragraph(&#39;Row 1=
, Col 1 wide data wide data wide data wide data&#39;, styles[&#39;Normal&#3=
9;]), &#39;Row 1, Col 2 wide data wide data wide data&#39;, &#39;Row 1, Col=
 3 wide data wide data wide data&#39;]<br>]<br><br>doc =3D SimpleDocTemplat=
e(&quot;table_endswidth.pdf&quot;, pagesize=3Dletter)<br>story =3D []<br><b=
r>colwidths =3D [None, &quot;20%&quot;, None] <br>table =3D Table(data, col=
Widths=3Dcolwidths)<br><br>story.append(table)<br>doc.build(story)</div>
</blockquote></div><div><br clear=3D"all"></div><br><span class=3D"gmail_si=
gnature_prefix">-- </span><br><div dir=3D"ltr" class=3D"gmail_signature">Ro=
bin Becker<br></div>

--0000000000003c6eae06467436c6--

--===============6012344371152731635==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline