[reportlab-users] Weird error
Dick Kniep
reportlab-users@reportlab.com
03 Oct 2003 00:40:53 +0200
--=-kTKd9j3fYSwS9nz3hLGQ
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Hi there,
I am planning to use reportlab in a standard database solution. I have
written some code that produces a nice report if it is less than one
page. However if I have more than one page it gets in a loop, or if I
uncomment some "raise condition" in reportlab itself, I get an error.
However, I do not know how to solve this.
GenReportLab.py is my code (including testdata which makes it crash).
Here is the code from reportlab where the crash occurs (line 542 in
doctemplate.py)
else:
# this must be cleared when they are finally drawn!
## if hasattr(f,'postponed'):
if hasattr(f,'_postponed'):
message = "Flowable %s too large on page %d" %
(f.identity(30), self.page)
raise "LayoutError", message
#show us, it might be handy
#HACK = it seems within tables we sometimes
#get an empty paragraph that won't fit and this
#causes it to fall over. FIXME FIXME FIXME
## f.postponed = 1
f._postponed = 1
flowables.insert(0,f) # put the flowable
back
self.handle_frameEnd()
In the original code the raise "LayoutError" is commented, but then I
get into a loop. I just cannot figure out how it exactly works, so if
any of you could help me solve this, it would be much appreciated....
Kind regards,
D. Kniep
--=-kTKd9j3fYSwS9nz3hLGQ
Content-Disposition: attachment; filename=GenReportLab.py
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-python; name=GenReportLab.py; charset=ISO-8859-15
#--------------------------------------------------------------------------=
---
# Name: GenReport.py
# Purpose: Genereer XML voor Kugar voor zowel de layout als de data
#
# Author: Dick Kniep
#
# Created: 2003/28/06
# RCS-ID: $Id: GenReport.py,v 1.1.1.1 2003/07/09 09:23:36 dick Exp $
# Copyright: (c) 2002
# Licence: <your licence>
#--------------------------------------------------------------------------=
---
from xml.dom.ext.reader import Sax2
from xml.dom.ext import PrettyPrint
from xml.dom.DOMImplementation import implementation
from os import tempnam, system, remove, chmod, popen
from math import floor
from types import *
from string import split, upper, strip
from reportlab.platypus import SimpleDocTemplate, BaseDocTemplate, Paragrap=
h, Spacer, Table, TableStyle, PageTemplate
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.rl_config import defaultPageSize
from reportlab.lib.units import cm
from reportlab.platypus.frames import Frame
from reportlab.lib import colors
from mx.DateTime import *
HOOGTE=3D defaultPageSize[1]
BREEDTE =3D defaultPageSize[0]
VELDNM =3D 0
VELDHDR =3D 1
VLDTYPE =3D 2
VLDDEC =3D 3
FONTBREEDTE =3D 4.3
BESCHIKBAARBREEDTE =3D BREEDTE - 100
BESCHIKBAARHOOGTE =3D HOOGTE - 80
# from xml.dom import EMPTYNAMESPACE
Testdef =3D ( ('veld1','kopveld1',"int",None),
('veld2','header2','chr',None),
('veld3','datumkop','dat',None),
('veld4','tekstkop','txt',None),
('veld5','numeriek','num',2),
('kortvld1','teller',"int",None))
TestData =3D [ [123423,'veld2tekst kort','12-04-2003',"lange tekst die g=
ewrapped moet worden... Ik weet niet of dat goed lukt, maar ik ga het in ie=
der geval proberen, bovendien moet ik maar kijken wat de grootste lengte is=
die de routine aankan",1232300,2],
[543211,'Tekst van veld2 tamellijk lang','17-12-2002','Nog =
een kop, die niet gewrapped moet worden',-98.32,2],
[543211,'Tekst van veld3 tamellijk lang','17-12-2002','Nog =
een kop, die niet gewrapped moet worden',98.30,4],
[543211,'Tekst van veld4 tamellijk lang','17-12-2002','Nog =
een kop, die niet gewrapped moet worden',-98.30,4],
[543211,'Tekst van veld5 tamellijk lang','17-12-2002','Nog =
een kop, die niet gewrapped moet worden',9.830,4],
[543211,'Tekst van veld6 tamellijk lang','17-12-2002','Nog =
een kop, die niet gewrapped moet worden',9.830,4],
[543211,'Tekst van veld7 tamellijk lang','17-12-2002','Nog =
een kop, die niet gewrapped moet worden',98.30,4],
[543211,'Tekst van veld8 tamellijk lang','17-12-2002','Nog =
een kop, die niet gewrapped moet worden',98.30,4],
[543211,'Tekst van veld9 tamellijk lang','17-12-2002','Nog =
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld10 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld11 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld12 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[5432114378,'Tekst van veld13 tamellijk lang','17-12-2002',=
'Nog een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld15 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld16 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld17 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[5432115,'Tekst van veld18 tamellijk lang','17-12-2002','No=
g een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld20 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld21 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld22 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld23 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld24 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld25 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld26 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld27 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld28 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld29 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld30 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld31 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld32 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld33 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld35 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld36 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld37 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld38 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
# [543211,'Tekst van veld39 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld40 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld90 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld91 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[543211,'Tekst van veld92 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,4],
[54232,'Tekst van veld193 tamellijk lang','17-12-2002','Nog=
een kop, die niet gewrapped moet worden',9830,6]]
#!/bin/env python
#copyright ReportLab Inc. 2000
#see license.txt for license details
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/platypus/t=
est/testtables.py?cvsroot=3Dreportlab
#$Header: /cvsroot/reportlab/reportlab/test/test_platypus_tables.py,v 1.3 2=
002/07/24 19:56:38 andy_robinson Exp $
__version__=3D''' $Id: test_platypus_tables.py,v 1.3 2002/07/24 19:56:38 an=
dy_robinson Exp $ '''
__doc__=3D'Test script for reportlab.tables'
from reportlab.test import unittest
from reportlab.test.utils import makeSuiteForClasses
#from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyl=
e
#from reportlab.lib.units import inch
=20
def _doNothing(canvas, doc):
"Dummy callback for onPage"
pass
class GenReport:
"""=20
Hoofdclass voor het genereren van een rapport op basis van Kugar,
=20
Doorgegeven wordt de titel van de lijst, de koppen en velden die afgedr=
ukt=20
worden. Dit is een lijst of een tuple met per af te drukken veld de vel=
dnaam,
de kop die boven de lijst moet komen te staan, vervolgens het type en d=
aarna het=20
aantal weer te geven decimalen.
=20
Daarnaast wordt de data doorgegeven die afgedrukt moet worden. Dit is e=
en list=20
van lists of tuples. De volgorde van de velden in de data moet PRECIES =
overeenkomen
met de veldvolgorde in de definitie.
=20
Tenslotte wordt doorgegeven of er eerst een voorbeeld op het scherm get=
oond
moet worden. Default is dat het afdrukken direct start.
=20
De breedte van de kolommen wordt berekend op basis van het maximaal aan=
tal
characters dat aangetroffen wordt in een af te drukken lijst, waarbij d=
e eerste=20
100 rijen genomen worden om de breedte te bepalen.
=20
Als eerste wordt het object GenReportDef aangemaakt. Dan worden de eers=
te 100
rijen doorgegeven tezamen met de lijstkoppen.
"""
=20
def __init__(self, reporthdr, fldhdrs, repdata, medewerker=3D'',
directprint=3DTrue, kutfile=3DNone, kudfile=3DNone)=
: =20
self.reporthdr =3D reporthdr
self.fldhdrs =3D fldhdrs
self.medewerker =3D medewerker
self.directprint =3D directprint
self.repdata =3D repdata
=20
doc =3D VerySimpleDocument('/tmp/CVStemp.pdf', pagesize=3D(BREEDTE,=
HOOGTE), showBoundary=3D0)
self.docstyles =3D getSampleStyleSheet()
# BESCHIKBAARBREEDTE =3D BREEDTE - self.doc.rightMargin - self.doc.l=
eftMargin
# BESCHIKBAARHOOGTE =3D HOOGTE - self.doc.bottomMargin - self.doc.to=
pMargin
=20
lst =3D []
kop =3D []
self.breedte =3D []
# doc.hdr =3D Paragraph(self.reporthdr,self.docstyles['Title'])
# doc.hdr.wrap(1*cm, HOOGTE)
=20
for vldnm, vldkop, type, dec in fldhdrs:
kop.append(Paragraph(vldkop, self.docstyles['BodyText']))
# self.breedte.append(len(vldkop)*FONTBREEDTE)
self.CalcBreedte()
=20
tabStyle =3D TableStyle ([ ('LINEABOVE',(0,0),(-1,0),1,colors.bl=
ack),
('LINEBELOW',(0,0),(-1,0),1,colors.blac=
k),
('VALIGN',(0,0),(-1,-1),'TOP')] )
tp =3D []
rh =3D [17]
for rec in repdata:
r =3D []
n =3D 0
rh.append(0)
for fld in rec:
print fld
if self.fldhdrs[n][VLDTYPE] in ("txt","chr"):
p =3D Paragraph(fld,self.docstyles['BodyText'])
r.append(p)
elif self.fldhdrs[n][VLDTYPE] =3D=3D "int":
r.append(str(fld))
tabStyle.add('ALIGN',(n,0),(n,-1),'RIGHT')
elif self.fldhdrs[n][VLDTYPE] =3D=3D "num":
r.append(self.MaskedOutput(fld,self.fldhdrs[n][VLDDEC])=
) # opmaak met decimalen!!!
tabStyle.add('ALIGN',(n,0),(n,-1),'RIGHT')
elif self.fldhdrs[n][VLDTYPE] =3D=3D "dat":
r.append(fld)
# if not type(fld) is StringType:
# r.append(fld.strftime('%d-%m-%Y'))
# elif type(fld) is StringType:
# r.append(fld)
# else: raise "Invalid FieldType " + type(fld) + ", cann=
ot be converted to string"
else:
raise "Invalid type " + self.fldhdrs[n][VLDTYPE]
n +=3D 1
tp.append(r)
h =3D [kop] + tp
self.nr_kols0 =3D len(kop) - 1
self.nr_rec0 =3D len(h) - 1
=20
self.t =3D Table(h, colWidths=3Dself.breedte, repeatRows=3D0)
self.t.setStyle(tabStyle)
=20
doc.build([self.t],onLaterPages=3Dself.onNewPage, onFirstPage=3Dsel=
f.onFirstPage)
def MaskedOutput(self, value, dec):
p =3D str(round(value*10**dec))
p =3D p[0:len(p)-2]
e =3D p[0:len(p)-dec] + ',' + p[len(p)-dec:]
return e
=20
def onNewPage(self, canvas, doc):
"""
Routine die de vaste kop afdrukt
"""
print "ik kom in NewPage"
canvas.saveState()
canvas.setFont('Times-Roman',20)
canvas.drawCentredString(BREEDTE/2, HOOGTE - 60,self.reporthdr)
canvas.restoreState()
def onFirstPage(self, canvas, doc):
"""
Routine die de vaste kop afdrukt
"""
print "ik kom in FirstPage"
canvas.saveState()
canvas.setFont('Times-Roman',20)
canvas.drawCentredString(BREEDTE/2, HOOGTE - 60,self.reporthdr)
canvas.restoreState()
=20
def CalcBreedte(self):
"""
Bereken breedte in characters en vervolgens in cm per kolom
=20
FONTBREEDTE is een grove benadering. De hoogte van de kolom wordt a=
utomatische=20
aangepast aan het aantal regels dat werkelijk geprint wordt.
"""
rn =3D 0
# p =3D Paragraph(str(self.repdata[0][1]),self.docstyles['BodyText']=
)
veldbr =3D [0]* len(self.fldhdrs)
maxbr =3D [0] * len(self.fldhdrs)
while rn < 100:
n =3D 0
for fld in self.repdata[rn]:
veldbr[n] +=3D len(str(fld))
if maxbr[n] < len(str(fld)): maxbr[n] =3D len(str(fld))
n +=3D 1
rn +=3D 1
if rn >=3D len(self.repdata): break
charbreedte =3D map(lambda br: round(br/rn),veldbr)
=20
# minimale breedte is breedte van de kop
tot =3D 0
for n in range(len(charbreedte)):
if len(self.fldhdrs[n][VELDHDR]) > charbreedte[n]: charbreedte[=
n] =3D len(self.fldhdrs[n][VELDHDR])
if charbreedte[n] + 4 > maxbr[n] and charbreedte[n] < maxbr[n]:=
charbreedte[n] =3D maxbr[n]
tot +=3D charbreedte[n]
=20
self.breedte =3D [0]*len(charbreedte)
ht =3D 0
hvt =3D 0
for n in range(len(charbreedte)):
if charbreedte[n] =3D=3D maxbr[n] or charbreedte[n] =3D=3D len(=
self.fldhdrs[n][VELDHDR]):=20
self.breedte[n] =3D FONTBREEDTE * (charbreedte[n] + 2)
ht +=3D self.breedte[n]
else:=20
hvt +=3D charbreedte[n] + 2
self.breedte[n] =3D -1
if ht > BESCHIKBAARBREEDTE: raise 'Te veel kolommen met vaste breed=
te'
=20
rest =3D BESCHIKBAARBREEDTE - ht
for n in range(len(charbreedte)):
if self.breedte[n] =3D=3D -1:
self.breedte[n] =3D int(rest * float(charbreedte[n]/hvt))
class VerySimpleDocument(BaseDocTemplate):
def build(self,flowables,onFirstPage=3D_doNothing, onLaterPages=3D_doNo=
thing):
"""build the document using the flowables. Annotate the first page=
using the onFirstPage
function and later pages using the onLaterPages function. T=
he onXXX pages should follow
the signature
def myOnFirstPage(canvas, document):
# do annotations and modify the document
...
The functions can do things like draw logos, page numbers,
footers, etcetera. They can use external variables to vary
the look (for example providing page numbering or section na=
mes).
"""
self._calc() #in case we changed margins sizes etc
print '----------------------build document'
print self.leftMargin=20
print self.bottomMargin=20
print self.width
print self.height
print self.pagesize
=20
frameT =3D Frame(self.leftMargin, self.bottomMargin, self.width, se=
lf.height, id=3D'normal')
self.addPageTemplates([PageTemplate(id=3D'First',frames=3DframeT, o=
nPage=3DonFirstPage,pagesize=3Dself.pagesize)])
# if onFirstPage is _doNothing and hasattr(self,'onFirstPage'):
# self.pageTemplates[0].beforeDrawPage =3D self.onFirstPage
BaseDocTemplate.build(self,flowables)
class KugarReport:
"""
Met behulp van deze class wordt output gegenereerd op basis van een ree=
ds
bestaande kugar definitiefile
"""
def __init__(self, kutfile):
self.kutfile =3D kutfile
self.document =3D implementation.createDocument(None,None,None)
self.ListData =3D self.document.createElement("KugarData")
self.document.appendChild(self.ListData)
self.fldhdrs =3D {}
=20
def detailhdrs(self, hdrs, lvl):
self.fldhdrs[lvl] =3D hdrs
=20
def procdetrecord(self, lvl, datarec):
DetailRij =3D self.document.createElement("Row")
DetailRij.setAttribute('level', str(lvl))
n =3D 0
for fld in self.fldhdrs[lvl]:
if type(datarec[n]) is StringType:r =3D datarec[n].decode('iso-=
8859-1')
elif type(datarec[n]) is IntType or type(datarec[n]) is FloatTy=
pe: r =3D `datarec[n]`
else: r =3D datarec[n]
DetailRij.setAttribute(fld,r)
n +=3D 1
=20
self.ListData.appendChild(DetailRij)
def printreport(self, directprint=3DTrue, kudfile=3D'/tmp/KugarReport.k=
ud'):
f =3D open(kudfile,'w')
PrettyPrint(self.document,f)
f.close()
chmod(kudfile, 777)
p =3D ExecKugar().KugarPrint(self.kutfile, kudfile, directprint)
=20
class ExecKugar:
def KugarPrint(self, kutfile, kudfile, directprint, genkutfile=3DFalse)=
:
kugar_version =3D popen('kugar --version')
p =3D split(kugar_version.read())
next =3D False
for v in p:
if next:=20
KugarVersie =3D v
break
if upper(v[0:5]) =3D=3D 'KUGAR': next =3D True
if KugarVersie < '1.2.90':
prtcommand =3D 'kugar -r ' + kutfile + ' -d ' + kudfile
elif directprint:
prtcommand =3D 'kugar --print --template ' + kutfile + ' ' + ku=
dfile
else:
prtcommand =3D 'kugar --template ' + kutfile + ' ' + kudfile
system(prtcommand)
=20
try:
remove(kudfile)
except:
pass
if genkutfile:
try:
remove(kutfile)
except:
pass
def getstyles():
styles =3D []
for i in range(5):
ts =3D [('ALIGN', (0,0), (-1,-1), 'LEFT')
, ('VALIGN', (0,0), (-1,-1), 'MIDDLE')=20
, ('GRID', (0,0), (-1,-1), 0.25, colors.black)
, ('BACKGROUND', (0,1), (1,2), colors.blue)
, ('BACKGROUND', (1,1), (2,2), colors.red) ]
if i =3D=3D 1:
ts.append(('SPAN', (0,1), (2,1)))
ts.append(('SPAN', (1,1), (2,2)))
if i =3D=3D 2:
ts.append(('SPAN', (0,1), (1,2)))
if i =3D=3D 3:
ts.append(('SPAN', (0,1), (2,2)))
if i =3D=3D 4:
ts.append(('SPAN', (0,1), (2,2)))
styles.append(TableStyle(ts))
return styles
=20
def runtest():
doc =3D SimpleDocTemplate('/tmp/test_platypus_tables_spanning.pdf', pag=
esize=3D(BREEDTE, HOOGTE), showBoundary=3D1)
docstyles =3D getSampleStyleSheet()
lst =3D [Paragraph('Dit is een titel',docstyles['Title'])]
styles =3D getstyles()
for i in range(len(styles)):
style =3D styles[i]
if i =3D=3D 4:
t =3D getTable([16,16,16])
else:
t =3D getTable([None,None,None])
t.setStyle(style)
lst.append(Paragraph(t,docstyles['BodyText']))
lst.append(Spacer(0,12))
doc.build(lst)
def run():
doc =3D SimpleDocTemplate('/tmp/test_platypus_tables_spanning.pdf', pag=
esize=3D(BREEDTE, HOOGTE), showBoundary=3D1)
docstyles =3D getSampleStyleSheet()
lst =3D []
kop =3D []
breedte =3D []
doc.hdr =3D Paragraph("Titel",docstyles['Title'])
doc.hdr.wrap(1*cm, HOOGTE)
for vlnm, vldkop, type, dec in Testdef:
kop.append(vldkop)
breedte.append(len(vldkop)* 8)
tp =3D []
rh =3D [17]
for rec in TestData:
r =3D []
n =3D 0
rh.append(0)
for fld in rec:
p =3D Paragraph(str(fld),docstyles['BodyText'])
s =3D p.minWidth()
if breedte[n] < s: breedte[n] =3D s
p.wrap(breedte[n],HOOGTE)
r.append(p)
if rh[-1] < p.height: rh[-1] =3D p.height
rh[-1] +=3D 15
tp.append(r)
h =3D [kop] + tp
styles =3D getstyles()
=20
t =3D Table(h, colWidths=3Dbreedte, style=3D [ ('LINEABOVE',(0,0),(l=
en(kop),0),1,colors.black),
('LINEBELOW',(0,0),(len(kop=
),0),1,colors.black)],=20
rowHeights=3Drh, repeatRows=3D1)
t.setStyle(TableStyle([('ALIGN',(0,0),(0,len(h)-1),'RIGHT')]))
lst.append(t)
=20
doc.build(lst, onLaterPages=3DonNewPage, onFirstPage=3DonNewPage)
#def onNewPage(canvas, template):
# canvas.saveState()
# canvas.setFont('Times-Bold',16)
# template.hdr.drawOn(canvas, BREEDTE/2, HOOGTE - 60)
# canvas.restoreState()
class TablesTestCase(unittest.TestCase):
"Make documents with tables"
def test0(self):
"Make a document full of tables"
GenReport("Testrapport",Testdef,TestData,"Pietje Puk")
def makeSuite():
return makeSuiteForClasses(TablesTestCase)
#noruntests
if __name__ =3D=3D "__main__":
unittest.TextTestRunner().run(makeSuite())
--=-kTKd9j3fYSwS9nz3hLGQ--