[reportlab-users] How are split, wrap, wrapOn supposed to work?

777 views
Skip to first unread message

Henning von Bargen

unread,
Oct 29, 2014, 12:25:56 PM10/29/14
to reportl...@lists2.reportlab.com
Hi all,

after a long, long time I'm finally trying to make Wordaxe work with
ReportLab again (RL 3.1.8),
mainly because I'm going to use it in a commercial application.

The test case "test1" from the file
c:\wordaxe\trunk\tests\test_platypus_paragraphs.py
runs into an endless loop and I think this could be a bug in RL.

Adding print statements like """print "_listWrapOn", availWidth"""
in several places the ReportLab code (mainly in platypus\flowables.py)
and raising an exception in c:\wordaxe-svn\trunk\rl\NewParagraph.py
in the i_wrap method like this:

...
def iter_widths(max_widths=max_widths):
# an iterator that repeats the last element infinitely
for w in max_widths: yield w
while True: yield w
width_iter = iter_widths()
max_width = width_iter.next()
if max_width < 0:
raise ValueError("Paragraph id %s: Max width is < 0: %s.
Text: %s" % (id(self), max_width, self.text[:200]))
...
I could see this output for the test case:

ImageAndFlowables wrap returning 298.0 123
67246472 wrap 55.0 268435455
65397704 wrap 298.0 696.661417323
65397704 i_wrap 298.0 696.661417323 [298.0, 298.0]
ImageAndFlowables wrap 298.0 673.161417323
ImageAndFlowables _findSplit -3.0 122.2
65388360 wrap -3.0 268435455
65388360 i_wrap -3.0 268435455 [-3.0, -3.0]
E
======================================================================
ERROR: test1 (__main__.ParagraphSplitTestCase)
This makes one long multi-page paragraph.
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_platypus_paragraphs.py", line 317, in test1
doc.multiBuild(story)
File
"c:\Python27\lib\site-packages\reportlab\platypus\doctemplate.py", line
970, in multiBuild
self.build(tempStory, **buildKwds)
File
"c:\Python27\lib\site-packages\reportlab\platypus\doctemplate.py", line
890, in build
self.handle_flowable(flowables)
File
"c:\Python27\lib\site-packages\reportlab\platypus\doctemplate.py", line
773, in handle_flowab
le
if frame.add(f, canv, trySplit=self.allowSplitting):
File "c:\Python27\lib\site-packages\reportlab\platypus\frames.py",
line 161, in _add
w, h = flowable.wrap(aW, h)
File "c:\Python27\lib\site-packages\reportlab\platypus\flowables.py",
line 1195, in wrap
W,H0,self._C0,self._C1 = self._findSplit(canv,self._iW,aH)
File "c:\Python27\lib\site-packages\reportlab\platypus\flowables.py",
line 1266, in _findSplit
w,h = f.wrapOn(canv,availWidth,0xfffffff)
File "c:\Python27\lib\site-packages\reportlab\platypus\flowables.py",
line 121, in wrapOn
w, h = self.wrap(aW,aH)
File "c:\wordaxe-svn\wordaxe\rl\NewParagraph.py", line 536, in wrap
return self.i_wrap(availW, availH, max_widths)
File "c:\wordaxe-svn\wordaxe\rl\NewParagraph.py", line 563, in i_wrap
raise ValueError("Paragraph id %s: Max width is < 0: %s. Text: %s" %
(id(self), max_width, self.
text[:200]))
ValueError: Paragraph id 65388360: Max width is < 0: -3.0. Text: The
CCCC of an integrated one box s
olution for advanced voice and data applications began with the
introduction of the IMACS. The IMACS
200 carries on that tradition with an integrated solution optimi

The long numbers are from id(self), the numbers after the description
are usually availWidth/availHeight

Note: I changed the test data text a bit to see that the story fragment
caused the endless loop:
story.append(Paragraph('Image larger than the frame',h3))
---> story.append(ImageAndFlowables(... <---- causing the loop

It is remarkable that ImageAndFlowables calls _findSplit with a negative
availWidth,
which in turns calls the flowable's wrap method (here: of the WordAxe
Paragraph instance)
with a negative instance:

ImageAndFlowables _findSplit -3.0 122.2
65388360 wrap -3.0 268435455

My gut feeling tells me that this is either a bug in RL or that I am
misunderstanding
something here.

So my main question is:

****************************************
How is a flowable's wrap method supposed to react when availWidth or
availHeight is <= 0?
****************************************

Running into an endless loop (as WordAxe does) is for sure not the best
solution.
I always assumed that wrap is only called after it has been assured that
everything fits.

And if this case is not expected, then it's a bug in ImageAndFlowable,
isn't it?

Furthermore, there are some bits in flowables.py that seem possibly
wrong:

1) In class Image:

def identity(self,maxLen=None):
r = Flowable.identity(self,maxLen)
if r[-4:]=='>...' and isinstance(self.filename,str):
r = "%s filename=%s>" % (r[:-4],self.filename)
return r

Shouldn't isinstance be used with basestr instead of str?

2) In ImageAndFlowables _findSplit method:

if H>availHeight:
from reportlab.platypus.paragraph import Paragraph
aH = availHeight-(H-h)
if isinstance(f,(Paragraph,Preformatted)):
leading = f.style.leading

Using isinstance here doesn't look very pythonish
and at the moment prevents this to work correctly with Wordaxe.


Best regards
Henning von Bargen
_______________________________________________
reportlab-users mailing list
reportl...@lists2.reportlab.com
https://pairlist2.pair.net/mailman/listinfo/reportlab-users

Henning von Bargen

unread,
Nov 7, 2014, 8:59:26 AM11/7/14
to reportl...@lists2.reportlab.com
A week ago I asked for help regarding split, wrap and wrapOn.

Unfortunately, I have not yet received any reply, that's why I'm asking
again.

While testing WordAxe, I found the test-case for ImageAndFlowables
running into an endless loop because the flowable's wrap method
is called with a negative availWidth argument and the Wordaxe
implementation
of a Paragraph obviously fails to handle this situation "in the right
way".

The question is: What is the right way then?
What should a flowable do if wrap is called with availWidth <= 0?
Or is that not supposed to happen at all?
And then, why does reportlab.platypus.paragraph.Paragraph work
with this test-case, but not wordaxe.rl.NewParagraph.Paragraph,
while it passes all the other tests?

I guess that only a member of the ReportLab team can answer this.

Henning

Andy Robinson

unread,
Nov 7, 2014, 9:15:14 AM11/7/14
to reportlab-users
Henning, I'm sorry about the lack of reply. We have been tied up with
a very complex series of software releases this week. And to be
honest I need some time to remember how this code works, it's been
about 10 years since I touched it :-(

My first impression is this:
> What should a flowable do if wrap is called with availWidth <= 0?
We never thought of it, but I guess raise a LayoutException?
> Or is that not supposed to happen at all?
see above.

We're working on core stuff next week - I hope. We will try to pull
your code down and look then.

- Andy
--
Andy Robinson
Managing Director
ReportLab Europe Ltd.
Thornton House, Thornton Road, Wimbledon, London SW19 4NG, UK
Tel +44-20-8405-6420

Robin Becker

unread,
Nov 7, 2014, 12:26:49 PM11/7/14
to reportlab-users
On 07/11/2014 13:59, Henning von Bargen wrote:
> A week ago I asked for help regarding split, wrap and wrapOn.
>
> Unfortunately, I have not yet received any reply, that's why I'm asking
> again.
>
> While testing WordAxe, I found the test-case for ImageAndFlowables
> running into an endless loop because the flowable's wrap method
> is called with a negative availWidth argument and the Wordaxe
> implementation
> of a Paragraph obviously fails to handle this situation "in the right
> way".
>
> The question is: What is the right way then?
> What should a flowable do if wrap is called with availWidth <= 0?
> Or is that not supposed to happen at all?

I don't think the frame code is supposed to get into this situation.
ImageAndFlowables might as it tries to lay out the flowables part itself. Even
so I think this should not happen for reasonable cases.

Effectively the wrap method of ImageAndFlowables is doing

1) determine the size of the image

2) Subtract the space from the availWidth x availHeight rectangle (at the top
left or top right). This leaves a narrow bit at the top of the rectangle.

3) Try to determine a split in the list of flowables that can use the narrow
bit. If that can't be done the narrow bit is supposed to be ignored. If the
split works then the trailing flowables are wrapped into the bit below the image
and the total height is determined.

The wrap method of the flowables will be called in several phases of the above.
If negative widths are passed to the wrap method it probably means the above
algorithm is doing something silly. However, I believe that negative witdhs just
mean you can't fit into the available space. I think wrap is supposed to return
the width it needs. Paragraphs are special in that they are supposed to occupy
the available width so normally the wrap method will return the availWidth
value. However, probably there is some minimum width >0 required to lay out the
para. I don't think wrap is supposed to raise any errors as it is an information
function.

If you have a simple example where wordaxe fails and our Paragraph class
succeeds I will try and work out what's happening given the image size etc etc.


> And then, why does reportlab.platypus.paragraph.Paragraph work
> with this test-case, but not wordaxe.rl.NewParagraph.Paragraph,
> while it passes all the other tests?
>
> I guess that only a member of the ReportLab team can answer this.
>
> Henning
.......
--
Robin Becker
Reply all
Reply to author
Forward
0 new messages