[reportlab-users] Miscalculation when using keepWithNext

Pierre Ossman ossman at cendio.se
Tue Dec 7 10:49:28 EST 2021

On 18/11/2021 10:49, Robin Becker wrote:
> I tried fairly hard to make an example like the one you suggest, but 
> it's too complex to really allow easy diagnosis.
> Looking at the internal code I was able to check that the KeepTogether 
> class that is used to replace keepWidthNext does provide access to the 
> space before and after attributes. Also at least in a really simple case 
> it does work. In the example below the keepWithNext group has a height 
> of 31. The heading stays with the body until the frame height, fh, falls 
> below 31 ie the required height for the group. When that happens things 
> just break. If you can supply a simple example I can try to make it go 
> wrong. It's not clear whether it's using spacers that causes the issue, 
> but I would argue that spaceBefore attributes handle that far better 
> than fixed space as they can vanish.

I had a look at making a stable test case, and I disproved part of my 
initial analysis. There *is* a bug handling zero width flowables. But 
there *is not* a bug handling spaceBefore.

The reason spaceBefore works is slight different from how the Frame does 
it though, which makes it non-obvious (but correct):

  * The _ContainerSpace base class propagates requests for spaceBefore 
to the first element, which is the appropriate thing to do
  * The Frame looks at spaceBefore before calculating the available 
height it then gives to wrap() and split(), which is also appropriate
  * _listWrapOn() always ignores spaceBefore for the first element, 
since it is either irrelevant, or already included in the available 
height calculated by the Frame

So it's just a bit non-obvious, but it seems correct. The problem is 
solely that zero width items are incorrectly discarded, which in turn 
makes _listWrapOn() consider the next item to be at the top, which it is 

The bug is fully present even without spacing though, so here is a test 
that exposes the issue as neatly as possible

from reportlab.platypus import BaseDocTemplate, PageTemplate, Flowable, 
FrameBreak, KeepTogether, PageBreak, Spacer, Frame
from reportlab.platypus import Paragraph, Preformatted, XBox
from reportlab.lib.styles import PropertySet, getSampleStyleSheet, 
from reportlab.lib.units import inch, cm
import sys

def testZeroWidth():
     class DocTemplate(BaseDocTemplate):
         _invalidInitArgs = ('pageTemplates',)
         def __init__(self, *args, **kw):
             super().__init__(*args, **kw)

             # Two frames, each 100pts high
             frame1 = Frame(inch, 5.6*inch, 6*inch, 100,
                            showBoundary=1, id='F1',
                            leftPadding=0, rightPadding=0,
                            topPadding=0, bottomPadding=0)
             frame2 = Frame(inch, 1.0*inch, 6*inch, 100,
                            showBoundary=1, id='F2',
                            leftPadding=0, rightPadding=0,
                            topPadding=0, bottomPadding=0)

     class KeepedXBox(XBox):
         def __init__(self, width, height, text = 'A Box', *,
             super().__init__(width, height, text)
             self.keepWithNext = keepWithNext

     story = [
                   XBox(4*inch, 50, 'top para'),
             KeepedXBox(0, 20, 'spacer', keepWithNext=True),
             KeepedXBox(4*inch, 20, 'heading', keepWithNext=True),
             KeepedXBox(4*inch, 20, 'body para', keepWithNext=False),

     doc = DocTemplate('test_zerowidth.pdf')

if __name__=='__main__':

Pierre Ossman           Software Development
Cendio AB               https://cendio.com
Teknikringen 8          https://twitter.com/ThinLinc
583 30 Linköping        https://facebook.com/ThinLinc
Phone: +46-13-214600

A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?

More information about the reportlab-users mailing list