[reportlab-users] Broken PDFs with multiBuild and file objects

Robin Becker reportlab-users@reportlab.com
Thu, 2 Jan 2003 11:15:27 +0000

In article <174400000.1041463216@galadriel.hohoff.bogus>, Holger Hoffmann
<hohoff@rz.uni-potsdam.de> writes
>BaseDocTemplate.multiBuild with a file object as parameter
>seems to produce a broken pdf document. If I use a filename
>as parameter all goes well. With a file object as parameter
>a broken pdf is generated. I've attached a script which
>demostrates this.
>The problem is that BaseDocTemplate.multiBuild makes multiple
>passes and generates one complete pdf document in each pass. If
>I use a filename as parameter to multiBuild, PDFDocument.SaveToFile
>opens and closes the file in every pass. If I use a file
>object as parameter, I get 2 pdf documents in one file.
>... Holger
.....OK it seems my preliminary fix got elided somehow.

The problem is this, the file object needs to be reset each time it goes through the
build loop. There are three cases

1) filename
2) file like object with write/tell/seek
3) file like object with write only (eg socket)

The fix is fairly obvious for 2, but for 3 it's not clear whether we should use a null
writable for the earlier iterations and do a final extra iteration with the proper
filename value to get the output or
perhaps use a StringIO.

my fix looks like this

RCS file: /cvsroot/reportlab/reportlab/platypus/doctemplate.py,v
retrieving revision 1.57
diff -r1.57 doctemplate.py
>         # attempt to fix the filename is a 'file' problem
>         isFile = getattr(filename,'write',None)
>         if isFile:
>             hasSeek = getattr(filename,'seek',None)
>             if hasSeek:
>                 fLoc = filename.tell()
>             else:
>                 class _DUMMYFILE:
>                     def __init__(self,filename):
>                         self._filename = filename
>                     def write(self,bytes): pass
>                     def close(self): pass
>                 filename = _DUMMYFILE(filename)
>             if passes and isFile and hasSeek: filename.seek(fLoc)
<                 ## print 'OK'
>                 if isFile and not hasSeek:
>                     filename = filename._filename
<             ## else:
<                 ## print 'failed'
Robin Becker