[reportlab-users] Weird error

Dick Kniep reportlab-users@reportlab.com
05 Oct 2003 23:25:25 +0200


Has onyone taken a look at this? Please help me.....

On Fri, 2003-10-03 at 00:40, Dick Kniep wrote:
> 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
> 
> ----
> 

> #-----------------------------------------------------------------------------
> # 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, Paragraph, 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= defaultPageSize[1]
> BREEDTE = defaultPageSize[0]
> VELDNM = 0
> VELDHDR = 1
> VLDTYPE = 2
> VLDDEC = 3
> FONTBREEDTE = 4.3
> BESCHIKBAARBREEDTE = BREEDTE - 100
> BESCHIKBAARHOOGTE = HOOGTE - 80
> 
> # from xml.dom import EMPTYNAMESPACE
> 
> 
> Testdef =   (   ('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 =  [   [123423,'veld2tekst kort','12-04-2003',"lange tekst die gewrapped moet worden... Ik weet niet of dat goed lukt, maar ik ga het in ieder 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','Nog 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/test/testtables.py?cvsroot=reportlab
> #$Header: /cvsroot/reportlab/reportlab/test/test_platypus_tables.py,v 1.3 2002/07/24 19:56:38 andy_robinson Exp $
> __version__=''' $Id: test_platypus_tables.py,v 1.3 2002/07/24 19:56:38 andy_robinson Exp $ '''
> __doc__='Test script for reportlab.tables'
> 
> from reportlab.test import unittest
> from reportlab.test.utils import makeSuiteForClasses
> 
> #from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle
> #from reportlab.lib.units import inch
>             
> def _doNothing(canvas, doc):
>     "Dummy callback for onPage"
>     pass
> 
> class GenReport:
>     """ 
>     Hoofdclass voor het genereren van een rapport op basis van Kugar,
>     
>     Doorgegeven wordt de titel van de lijst, de koppen en velden die afgedrukt 
>     worden. Dit is een lijst of een tuple met per af te drukken veld de veldnaam,
>     de kop die boven de lijst moet komen te staan, vervolgens het type en daarna het 
>     aantal weer te geven decimalen.
>     
>     Daarnaast wordt de data doorgegeven die afgedrukt moet worden. Dit is een list 
>     van lists of tuples. De volgorde van de velden in de data moet PRECIES overeenkomen
>     met de veldvolgorde in de definitie.
>     
>     Tenslotte wordt doorgegeven of er eerst een voorbeeld op het scherm getoond
>     moet worden. Default is dat het afdrukken direct start.
>     
>     De breedte van de kolommen wordt berekend op basis van het maximaal aantal
>     characters dat aangetroffen wordt in een af te drukken lijst, waarbij de eerste 
>     100 rijen genomen worden om de breedte te bepalen.
>     
>     Als eerste wordt het object GenReportDef aangemaakt. Dan worden de eerste 100
>     rijen doorgegeven tezamen met de lijstkoppen.
>     """
>     
>     def __init__(self, reporthdr, fldhdrs, repdata, medewerker='',
>                         directprint=True, kutfile=None, kudfile=None):        
> 
>         self.reporthdr = reporthdr
>         self.fldhdrs = fldhdrs
>         self.medewerker = medewerker
>         self.directprint = directprint
>         self.repdata = repdata
>         
>         doc = VerySimpleDocument('/tmp/CVStemp.pdf', pagesize=(BREEDTE, HOOGTE), showBoundary=0)
>         self.docstyles = getSampleStyleSheet()
> #        BESCHIKBAARBREEDTE = BREEDTE - self.doc.rightMargin - self.doc.leftMargin
> #        BESCHIKBAARHOOGTE = HOOGTE - self.doc.bottomMargin - self.doc.topMargin
>         
>         lst = []
>         kop = []
>         self.breedte = []
> #        doc.hdr = Paragraph(self.reporthdr,self.docstyles['Title'])
> #        doc.hdr.wrap(1*cm, HOOGTE)
>     
>         for vldnm, vldkop, type, dec in fldhdrs:
>             kop.append(Paragraph(vldkop, self.docstyles['BodyText']))
> #            self.breedte.append(len(vldkop)*FONTBREEDTE)
> 
>         self.CalcBreedte()
>     
> 
>         tabStyle = TableStyle ([    ('LINEABOVE',(0,0),(-1,0),1,colors.black),
>                                     ('LINEBELOW',(0,0),(-1,0),1,colors.black),
>                                     ('VALIGN',(0,0),(-1,-1),'TOP')] )
> 
>         tp = []
>         rh = [17]
>         for rec in repdata:
>             r = []
>             n = 0
>             rh.append(0)
>             for fld in rec:
>                 print fld
>                 if self.fldhdrs[n][VLDTYPE] in ("txt","chr"):
>                     p = Paragraph(fld,self.docstyles['BodyText'])
>                     r.append(p)
>                 elif self.fldhdrs[n][VLDTYPE] == "int":
>                     r.append(str(fld))
>                     tabStyle.add('ALIGN',(n,0),(n,-1),'RIGHT')
>                 elif self.fldhdrs[n][VLDTYPE] == "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] == "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) + ", cannot be converted to string"
>                 else:
>                     raise "Invalid type " + self.fldhdrs[n][VLDTYPE]
>                 n += 1
>             tp.append(r)
> 
>         h = [kop] + tp
>         self.nr_kols0 = len(kop) - 1
>         self.nr_rec0 = len(h) - 1
>         
>         self.t = Table(h, colWidths=self.breedte, repeatRows=0)
>         self.t.setStyle(tabStyle)
>         
>         doc.build([self.t],onLaterPages=self.onNewPage, onFirstPage=self.onFirstPage)
> 
>     def MaskedOutput(self, value, dec):
>         p = str(round(value*10**dec))
>         p = p[0:len(p)-2]
>         e = p[0:len(p)-dec] + ',' + p[len(p)-dec:]
>         return e
>         
>     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()
>     
> 
>     def CalcBreedte(self):
>         """
>         Bereken breedte in characters en vervolgens in cm per kolom
>         
>         FONTBREEDTE is een grove benadering. De hoogte van de kolom wordt automatische 
>         aangepast aan het aantal regels dat werkelijk geprint wordt.
>         """
>         rn = 0
> #        p = Paragraph(str(self.repdata[0][1]),self.docstyles['BodyText'])
>         veldbr = [0]* len(self.fldhdrs)
>         maxbr = [0] * len(self.fldhdrs)
>         while rn < 100:
>             n = 0
>             for fld in self.repdata[rn]:
>                 veldbr[n] += len(str(fld))
>                 if maxbr[n] < len(str(fld)): maxbr[n] = len(str(fld))
>                 n += 1
>             rn += 1
>             if rn >= len(self.repdata): break
>         charbreedte = map(lambda br: round(br/rn),veldbr)
>         
> # minimale breedte is breedte van de kop
>         tot = 0
>         for n in range(len(charbreedte)):
>             if len(self.fldhdrs[n][VELDHDR]) > charbreedte[n]: charbreedte[n] = len(self.fldhdrs[n][VELDHDR])
>             if charbreedte[n] + 4 > maxbr[n] and charbreedte[n] < maxbr[n]: charbreedte[n] = maxbr[n]
>             tot += charbreedte[n]
>             
>         self.breedte = [0]*len(charbreedte)
>         ht = 0
>         hvt = 0
>         for n in range(len(charbreedte)):
>             if charbreedte[n] == maxbr[n] or charbreedte[n] == len(self.fldhdrs[n][VELDHDR]): 
>                 self.breedte[n] =  FONTBREEDTE * (charbreedte[n] + 2)
>                 ht += self.breedte[n]
>             else: 
>                 hvt += charbreedte[n] + 2
>                 self.breedte[n] = -1
> 
> 
>         if ht > BESCHIKBAARBREEDTE: raise 'Te veel kolommen met vaste breedte'
>         
>         rest = BESCHIKBAARBREEDTE - ht
>         for n in range(len(charbreedte)):
>             if self.breedte[n] == -1:
>                 self.breedte[n] = int(rest * float(charbreedte[n]/hvt))
> 
> class VerySimpleDocument(BaseDocTemplate):
>     def build(self,flowables,onFirstPage=_doNothing, onLaterPages=_doNothing):
>         """build the document using the flowables.  Annotate the first page using the onFirstPage
>                function and later pages using the onLaterPages function.  The 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 names).
>         """
>         self._calc()    #in case we changed margins sizes etc
>         print '----------------------build document'
>         print self.leftMargin 
>         print self.bottomMargin 
>         print self.width
>         print self.height
>         print self.pagesize
>         
>         frameT = Frame(self.leftMargin, self.bottomMargin, self.width, self.height, id='normal')
>         self.addPageTemplates([PageTemplate(id='First',frames=frameT, onPage=onFirstPage,pagesize=self.pagesize)])
> #        if onFirstPage is _doNothing and hasattr(self,'onFirstPage'):
> #            self.pageTemplates[0].beforeDrawPage = self.onFirstPage
>         BaseDocTemplate.build(self,flowables)
> 
> class KugarReport:
>     """
>     Met behulp van deze class wordt output gegenereerd op basis van een reeds
>     bestaande kugar definitiefile
>     """
>     def __init__(self, kutfile):
>         self.kutfile = kutfile
>         self.document = implementation.createDocument(None,None,None)
>         self.ListData = self.document.createElement("KugarData")
>         self.document.appendChild(self.ListData)
>         self.fldhdrs = {}
>         
>     def detailhdrs(self, hdrs, lvl):
>         self.fldhdrs[lvl] = hdrs
>     
>     def procdetrecord(self, lvl, datarec):
>         DetailRij = self.document.createElement("Row")
>         DetailRij.setAttribute('level', str(lvl))
>         n = 0
>         for fld in self.fldhdrs[lvl]:
>             if type(datarec[n]) is StringType:r = datarec[n].decode('iso-8859-1')
>             elif type(datarec[n]) is IntType or type(datarec[n]) is FloatType: r = `datarec[n]`
>             else: r = datarec[n]
>             DetailRij.setAttribute(fld,r)
>             n += 1
>         
>         self.ListData.appendChild(DetailRij)
> 
>     def printreport(self, directprint=True, kudfile='/tmp/KugarReport.kud'):
>         f = open(kudfile,'w')
>         PrettyPrint(self.document,f)
>         f.close()
>         chmod(kudfile, 777)
>         p = ExecKugar().KugarPrint(self.kutfile, kudfile, directprint)
>         
> class ExecKugar:
>     def KugarPrint(self, kutfile, kudfile, directprint, genkutfile=False):
> 
>         kugar_version = popen('kugar --version')
>         p = split(kugar_version.read())
>         next = False
>         for v in p:
>             if next: 
>                 KugarVersie = v
>                 break
>             if upper(v[0:5]) == 'KUGAR': next = True
> 
> 
>         if KugarVersie < '1.2.90':
>             prtcommand = 'kugar -r ' + kutfile + ' -d ' + kudfile
>         elif directprint:
>             prtcommand = 'kugar --print --template ' + kutfile + ' ' + kudfile
>         else:
>             prtcommand = 'kugar --template ' + kutfile + ' ' + kudfile
> 
>         system(prtcommand)
>      
>         try:
>             remove(kudfile)
>         except:
>             pass
> 
>         if genkutfile:
>             try:
>                 remove(kutfile)
>             except:
>                 pass
> 
> def getstyles():
>    styles = []
>    for i in range(5):
>        ts = [('ALIGN', (0,0), (-1,-1), 'LEFT')
>              , ('VALIGN', (0,0), (-1,-1), 'MIDDLE') 
>              , ('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 == 1:
>             ts.append(('SPAN', (0,1), (2,1)))
>             ts.append(('SPAN', (1,1), (2,2)))
>        if i == 2:
>             ts.append(('SPAN', (0,1), (1,2)))
>        if i == 3:
>             ts.append(('SPAN', (0,1), (2,2)))
>        if i == 4:
>             ts.append(('SPAN', (0,1), (2,2)))
>        styles.append(TableStyle(ts))
>    return styles
>        
> def runtest():
>     doc = SimpleDocTemplate('/tmp/test_platypus_tables_spanning.pdf', pagesize=(BREEDTE, HOOGTE), showBoundary=1)
>     docstyles = getSampleStyleSheet()
>     lst = [Paragraph('Dit is een titel',docstyles['Title'])]
>     styles = getstyles()
>     for i in range(len(styles)):
>         style = styles[i]
>         if i == 4:
>             t = getTable([16,16,16])
>         else:
>             t = getTable([None,None,None])
>         t.setStyle(style)
>         lst.append(Paragraph(t,docstyles['BodyText']))
>         lst.append(Spacer(0,12))
>     doc.build(lst)
> 
> def run():
>     doc = SimpleDocTemplate('/tmp/test_platypus_tables_spanning.pdf', pagesize=(BREEDTE, HOOGTE), showBoundary=1)
>     docstyles = getSampleStyleSheet()
>     lst = []
>     kop = []
>     breedte = []
>     doc.hdr = 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 = []
>     rh = [17]
>     for rec in TestData:
>         r = []
>         n = 0
>         rh.append(0)
>         for fld in rec:
>             p = Paragraph(str(fld),docstyles['BodyText'])
>             s = p.minWidth()
>             if breedte[n] < s: breedte[n] = s
>             p.wrap(breedte[n],HOOGTE)
>             r.append(p)
>             if rh[-1] < p.height: rh[-1] = p.height
>         rh[-1] += 15
>         tp.append(r)
> 
>     h = [kop] + tp
>     styles = getstyles()
>     
>     t = Table(h, colWidths=breedte, style= [    ('LINEABOVE',(0,0),(len(kop),0),1,colors.black),
>                                                 ('LINEBELOW',(0,0),(len(kop),0),1,colors.black)], 
>                     rowHeights=rh, repeatRows=1)
>     t.setStyle(TableStyle([('ALIGN',(0,0),(0,len(h)-1),'RIGHT')]))
>     lst.append(t)
>     
> 
>     doc.build(lst, onLaterPages=onNewPage, onFirstPage=onNewPage)
> 
> #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__ == "__main__":
>     unittest.TextTestRunner().run(makeSuite())