Sto facendo il mio primo programma utilizzando ReportLab dove non so in anticipo dove le interruzioni di pagina cadranno e ho problemi. Per mantenere le cose semplici sto usando il SimpleDocTemplate
. I miei compositi fluidi sono qualcosa del tipo:ReportLab LayoutError: troppo grande sulla pagina
flowables = [Paragraph("Some title", style=headerParagraphStyle),
Spacer(0, 10),
Paragraph("first paragraph", style=bodyParagraphStyle),
Paragraph("second paragraph", style=bodyParagraphStyle),
...
Paragraph("nth paragraph", style=bodyParagraphStyle),
PageBreak(),
Paragraph("Some title", style=headerParagraphStyle),
Spacer(0, 10),
Paragraph("first paragraph", style=bodyParagraphStyle),
Paragraph("second paragraph", style=bodyParagraphStyle),
...
Paragraph("mth paragraph", style=bodyParagraphStyle),
PageBreak(),
...]
Quando costruisco il mio PDF tutto va bene fino a quando il mio n
o m
o comunque molti paragrafi corpo in forma in una sola pagina, ma se corrono sopra, ottengo un errore come il seguente:
reportlab.platypus.doctemplate.LayoutError: Flowable <Paragraph at 0xb79800 frame=normal>20th paragraph: too large on page 3
Non riesco a trovare una buona ragione per cui questo continua a succedermi. Eventuali suggerimenti? Lo fa anche se rimuovo PageBreaks(). Tutti i paragrafi sono relativamente brevi, per lo più inferiori a una frase/riga.
ETA: Sto postando tutto il codice (con identificatori minori spogliati) che sta generando l'errore per me. L'ho convertito per leggere un file CSV, quindi ne ho pubblicato anche il contenuto. L'errore esatto che questo codice genera per me quando l'eseguo è:
lavoroTraceback (most recent call last): File "./spice_dev.py", line 355, in departmentReportDoc.build(eachDepartment.report, onFirstPage=onReportPage, onLaterPages=onReportPage) File "/usr/local/lib/python2.6/site-packages/reportlab/platypus/doctemplate.py", line 1010, in build BaseDocTemplate.build(self,flowables, canvasmaker=canvasmaker) File "/usr/local/lib/python2.6/site-packages/reportlab/platypus/doctemplate.py", line 777, in build self.handle_flowable(flowables) File "/usr/local/lib/python2.6/site-packages/reportlab/platypus/doctemplate.py", line 694, in handle_flowable raise LayoutError(ident) reportlab.platypus.doctemplate.LayoutError: Flowable Additional comments and suggestions for improvement: too large on page 3
Alcuni di debug mostra che l'errore è il risultato di questo paragrafo (anche se può essere altri compositi fluidi, a seconda della lunghezza del contenuto) cercando di diviso, rinviato e quindi non ancora in grado di essere diviso dopo la chiamata a handle_frameEnd()
. Suggerimenti?
spice.py:
#!/usr/local/bin/python
# vim: set fileencoding=latin-1
#import csv
import os
import os.path
import time
import numpy
import scipy.stats._support
#for debugging
import sys
import traceback
# imports for reportlab
from reportlab.platypus import *
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.pagesizes import LETTER, landscape, portrait
from reportlab.lib.units import inch
from reportlab.lib import colors
from reportlab.pdfgen import canvas
from reportlab.lib.enums import *
##########################
####### Constants ########
##########################
kNumberOfQuestions = 4
##########################
####### Reportlab ########
##########################
def _doNothing(canv, doc):
pass
headerParagraphStyle = ParagraphStyle("Header", fontName="Helvetica-Bold", fontSize=16, spaceAfter = .05*inch, alignment=TA_CENTER)
header2ParagraphStyle = ParagraphStyle("Header2", fontName="Helvetica-Bold", fontSize=14, spaceAfter = .1*inch, spaceBefore=.5*inch, alignment=TA_CENTER)
subheaderInfoParagraphStyle = ParagraphStyle("Subheader Info", fontName="Helvetica-Bold", fontSize=10, alignment=TA_CENTER)
questionParagraphStyle = ParagraphStyle("Question header", fontName="Helvetica-Bold", fontSize = 10, alignment=TA_LEFT)
commentParagraphStyle = ParagraphStyle("Comment", fontName="Helvetica", fontSize = 10, alignment=TA_LEFT)
instructorParagraphStyle = ParagraphStyle("Instructor Header", fontName="Helvetica", fontSize=10, alignment=TA_LEFT)
basicTableStyle = TableStyle(
[('FONT', (0, 0), (-1, 0), 'Helvetica-Bold', 9),
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('LINEBELOW', (0, 0), (-1, 0), 1, colors.black),
('INNERGRID', (0, 0), (-1, 0), 1, colors.black),
('FONT', (0, 1), (-1, -1), 'Helvetica', 9),
('ALIGN', (0, 1), (-1, 1), 'LEFT'),
('ALIGN', (1, 1), (-1, -1), 'CENTER'),
('LINEAFTER', (0, 1), (0, -1), 1, colors.black),
('LINEBEFORE', (1, 1), (-1, -1), 1, colors.black),
('ROWBACKGROUNDS', (0, 1), (-1, -1), (colors.white, (.9, .9, .9))),
('TOPPADDING', (1, 1), (-1, -1), 8)
])
statTableStyle = TableStyle(
[('FONT', (0, 0), (0, -1), 'Helvetica-Bold', 9),
('ALIGN', (0, 0), (0, -1), 'RIGHT'),
('INNERGRID', (0, 0), (-1, -1), 1, colors.black),
('FONT', (1, 0), (1, -1), 'Helvetica', 9),
('ALIGN', (1, 0), (1, -1), 'LEFT')
])
headerTableStyle = TableStyle(
[('FONT', (0, 0), (-1, 0), 'Helvetica', 8),
('FONT', (0, 1), (-1, 1), 'Helvetica-Bold', 8),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('LINEBELOW', (0, 0), (-1, 0), 1, colors.black),
('LINEAFTER', (0, 0), (-1, -1), 20, colors.white),
('LEFTPADDING', (0,0), (-1, -1), 15),
('RIGHTPADDING', (0, 0), (-1, -1), 15)
])
##########################
######## Classes #########
##########################
class Course:
def __init__(self):
self.prefix = ""
self.number = ""
self.section = ""
self.instructor = ""
self.email = ""
self.name = "None Found"
self.enrollment = 0
self.semester = ""
self.report = [] # subreport for the course
self.dataFile = []
def __repr__(self):
return self.prefix + " " + self.number + " " + self.section + " " + self.instructor
class Instructor:
def __init__(self):
self.name = ""
self.email = ""
self.courses = dict([])
self.report = []
self.dataFile = []
def __repr__(self):
return self.name + " " + self.email
class Department:
def __init__(self):
self.name = ""
self.instructors = dict([]) #contains Instructor objects
self.report = [] #subreport for the department
self.dataFile = []
def __repr__(self):
return self.name
class College:
def __init__(self):
self.name = ""
self.departments = dict([]) #contains Department objects
self.report = [] #subreport for the college
self.dataFile = []
def __repr__(self):
return self.name + ":" + `self.departments`
class University:
def __init__(self):
self.name = ""
self.colleges = dict([]) #contains College objects
def __repr__(self):
return self.name + ":" + `self.colleges`
#########################
### Utility Functions ###
#########################
def onReportPage(canv, doc):
#display general info at the top of every page
canv.setFont('Courier', 10)
canv.drawString(inch, 10.5*inch, "Wassamata U")
canv.drawString(inch, 10.35*inch, "Student Comments")
canv.drawString(5.75*inch, 10.5*inch, "Year/Term: " + uSemesterYear + "/" + uSemesterTerm)
canv.drawString(5.75*inch, 10.35*inch, " Semester: " + `semesterNumber`)
def xmlify(text):
return text.replace('&','&').replace('<','<').replace('>','>')
def semesterDescription(semesterNumber):
# reference semester is Spring 1964, i.e. semester 0
semesterNumber = semesterNumber/10
year = `1964 + (semesterNumber/3)`
term = "Spring"
if semesterNumber % 3 == 1:
term = "Summer"
elif semesterNumber % 3 == 2:
term = "Fall"
return year, term
#########################
######### Main ##########
#########################
# set up some options
# should have a ui later
# ugly, but quick
# used to get them on the top of every page
global uSemesterYear
global uSemesterTerm
print "\n"
university = University()
university.name = "Wassamata U"
commentsFile = open("spireport2.csv", "rb").read()
commentRecords = commentsFile.split("ô\r\n")
commentsArray = []
for commentRecord in commentRecords:
commentsArray.append(commentRecord.split("æ"))
commentsArray.pop()
print "Reading in the SPI file"
#read in data from file
for row in commentsArray:
#print row
# college
currentCollege = university.colleges.get(row[0])
if currentCollege == None:
currentCollege = College()
currentCollege.name = row[0].replace("/", " ")
university.colleges[row[0]] = currentCollege
#department
currentDepartment = currentCollege.departments.get(row[1])
if currentDepartment == None:
currentDepartment = Department()
currentDepartment.name = row[1].replace("/", " ")
currentCollege.departments[row[1]] = currentDepartment
#instructor
currentInstructor = currentDepartment.instructors.get(row[2] + row[3])
if currentInstructor == None:
currentInstructor = Instructor()
currentInstructor.name = row[3].replace("/", " ")
currentInstructor.email = row[2].replace("/", " ")
currentDepartment.instructors[row[2] + row[3]] = currentInstructor
#course
currentCourse = currentInstructor.courses.get(row[5] + row[6] + row[7])
if currentCourse == None:
currentCourse = Course()
currentCourse.prefix = row[5][:3]
currentCourse.number = row[5][3:]
currentCourse.section = row[6]
currentCourse.instructor = row[3]
currentCourse.email = row[2]
currentCourse.name = row[4]
currentCourse.semester = row[7]
currentCourse.enrollment = int(row[8])
currentInstructor.courses[row[5] + row[6] + row[7]] = currentCourse
data = row[9:9+kNumberOfQuestions]
currentCollege.dataFile.append(data) #split the data file by college for later
currentInstructor.dataFile.append(data)
currentDepartment.dataFile.append(data)
currentCourse.dataFile.append(data)
semesterNumber = int(university.colleges.values()[0].departments.values()[0].instructors.values()[0].courses.values()[0].semester)
uSemesterYear, uSemesterTerm = semesterDescription(semesterNumber)
reportDocContent = []
print "Processing the SPI comments"
for eachCollege in university.colleges.values():
print "\tProcessing " + eachCollege.name
collegeReportStartingIndex = len(reportDocContent)
reportDocContent.append(Spacer(0, 100))
reportDocContent.append(Paragraph("Student comments for " + eachCollege.name, headerParagraphStyle))
reportDocContent.append(PageBreak())
for eachDepartment in eachCollege.departments.values():
print "\t\tProcessing " + eachDepartment.name
departmentReportStartingIndex = len(reportDocContent)
reportDocContent.append(Spacer(0, 100))
reportDocContent.append(Paragraph("Student comments for " + eachDepartment.name, headerParagraphStyle))
reportDocContent.append(PageBreak())
for eachInstructor in eachDepartment.instructors.values():
print "\t\t\tProcessing " + eachInstructor.name
instructorReportStartingIndex = len(reportDocContent)
reportDocContent.append(Spacer(0, 100))
reportDocContent.append(Paragraph("Student comments for " + eachInstructor.name + ", " + eachInstructor.email, headerParagraphStyle))
reportDocContent.append(PageBreak())
for eachCourse in eachInstructor.courses.values():
courseReportStartingIndex = len(reportDocContent)
reportDocContent.append(Paragraph("<para leftIndent=54><b>Instructor Name:</b> " + eachCourse.instructor + "</para>", instructorParagraphStyle))
reportDocContent.append(Spacer(0, 10))
headerTableContent1 = [[eachDepartment.name + "/" + eachCollege.name, eachCourse.prefix + eachCourse.number + eachCourse.section, eachCourse.name], ["Department/School", "Course-Section Number", "Course Name"]]
headerTableContent2 = [[eachCourse.enrollment if eachCourse.enrollment > 0 else "Unknown",
len(eachCourse.dataFile),
("%.2f" % (float(len(eachCourse.dataFile))/eachCourse.enrollment*100) if eachCourse.enrollment != 0 else "0.00")],
["Number of Students Enrolled", "Number Responding", "% of Response"]]
reportDocContent.append(Table(headerTableContent1, style=headerTableStyle))
reportDocContent.append(Spacer(0, 10))
reportDocContent.append(Table(headerTableContent2, style=headerTableStyle))
i = 0
for i in range(0, kNumberOfQuestions):
question = ""
if i == 0:
question = "The thing(s) I like the MOST about this course:"
elif i == 1:
question = "The thing(s) I like the LEAST about this course:"
elif i == 2:
question = "What is your reaction to the method of evaluating your mastery of the course (i.e., testing, grading, out of class assignments (term papers), instructor feedback, etc.):"
elif i == 3:
question = "Additional comments and suggestions for improvement:"
reportDocContent.append(Spacer(0, 10))
reportDocContent.append(Paragraph(question, style=questionParagraphStyle))
reportDocContent.append(Spacer(0, 5))
commentParagraph = ""
for comments in eachCourse.dataFile:
if comments[i] != "":
commentParagraph += unicode(comments[i], 'latin-1') + "<br/>"
reportDocContent.append(Paragraph(commentParagraph, style=commentParagraphStyle))
eachCourse.report = reportDocContent[courseReportStartingIndex:]
reportDocContent.append(PageBreak())
eachInstructor.report = reportDocContent[instructorReportStartingIndex:]
eachDepartment.report = reportDocContent[departmentReportStartingIndex:]
eachCollege.report = reportDocContent[collegeReportStartingIndex:]
# build directory structure to put reports in
for eachCollege in university.colleges.values():
if (not os.path.exists(eachCollege.name)):
os.mkdir(eachCollege.name)
for eachDepartment in eachCollege.departments.values():
if (not os.path.exists(os.path.join(eachCollege.name, eachDepartment.name))):
os.mkdir(os.path.join(eachCollege.name, eachDepartment.name))
for eachInstructor in eachDepartment.instructors.values():
if (not os.path.exists(os.path.join(eachCollege.name, eachDepartment.name, eachInstructor.name + " - " + eachInstructor.email))):
os.mkdir(os.path.join(eachCollege.name, eachDepartment.name, eachInstructor.name + " - " + eachInstructor.email))
print "Building Comments Report PDFs"
for eachCollege in university.colleges.values():
print "\tBuilding Comments Report for " + eachCollege.name
collegeReportDoc = SimpleDocTemplate(os.path.join(eachCollege.name, eachCollege.name + " SPI Comments Report.pdf"), pagesize=portrait(LETTER), allowSplitting=1)
collegeReportDoc.leftMargin = .25*inch
collegeReportDoc.rightMargin = .25*inch
collegeReportDoc.bottomMargin = .25*inch
collegeReportDoc.build(eachCollege.report, onFirstPage=onReportPage, onLaterPages=onReportPage)
for eachDepartment in eachCollege.departments.values():
print "\t\tBuilding Comments Report for " + eachDepartment.name
departmentReportDoc = SimpleDocTemplate(os.path.join(eachCollege.name, eachDepartment.name, eachDepartment.name + " SPI Comments Report.pdf"), pagesize=portrait(LETTER), allowSplitting=1)
departmentReportDoc.leftMargin = .25*inch
departmentReportDoc.rightMargin = .25*inch
departmentReportDoc.bottomMargin = .25*inch
# import pdb; pdb.set_trace()
departmentReportDoc.build(eachDepartment.report, onFirstPage=onReportPage, onLaterPages=onReportPage)
print "\t\t\tBuilding Comments Reports for individual instructors"
for eachInstructor in eachDepartment.instructors.values():
instructorReportDoc = SimpleDocTemplate(os.path.join(eachCollege.name, eachDepartment.name, eachInstructor.name + " - " + eachInstructor.email, eachInstructor.name + " SPI Comments Report.pdf"), pagesize=portrait(LETTER), allowSplitting=1)
instructorReportDoc.leftMargin = .25*inch
instructorReportDoc.rightMargin = .25*inch
instructorReportDoc.bottomMargin = .25*inch
instructorReportDoc.build(eachInstructor.report, onFirstPage=onReportPage, onLaterPages=onReportPage)
#we do this one last because it's the biggest; otherwise it'd be at the beginning of the pdf report generation process
print "\tBuilding SPI Report for University"
reportDoc = SimpleDocTemplate("SPI Comments Report.pdf", pagesize=portrait(LETTER), allowSplitting=1)
reportDoc.leftMargin = .25*inch
reportDoc.rightMargin = .25*inch
reportDoc.bottomMargin = .25*inch
reportDoc.build(reportDocContent, onFirstPage=onReportPage, onLaterPages=onReportPage)
spireport2.csv:
College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æsample commentsææi like itæô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205æone with a line break; let's see what happensæææweird charactèrs áÈ-{ô College of Health & Public AffæCriminal Justice/Legal Studiesæ[email protected]æAn InstructoræFOUNDATIONS OF LAW ENFORCEMENTæCJE5021æ0001æ1370æ 7ææææô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205ææææô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205ææææô College of Health & Public AffæHealth Info Mgmtæ[email protected]æAn InstructoræMEDICAL TERMINOLOGYæHSC3537æ0M01æ1370æ 205ææææô College of Arts & HumanitiesæEnglishæ[email protected]æAn InstructoræHARLEM, HAITI, AND HAVANAæAML3615æ0001æ1370æ 35ææææô College of Arts & HumanitiesæEnglishæ[email protected]æAn InstructoræCONT AMERICAN WOMEN S FICTIONæAML3283æ0001æ1370æ 35ææææô College of Arts & HumanitiesæEnglishæ[email protected]æAn InstructoræPOST-WORLD WAR II FICTIONæLIT4303æ0M01æ1370æ 32ææææô College of Arts & HumanitiesæEnglishæ[email protected]æAn InstructoræMAJOR AMERICAN AUTHORSæAML4300æ0001æ1370æ 33ææææô College of Arts & HumanitiesæEnglishæ[email protected]æAn InstructoræPRACTICAL CRITICISMæENG3010æ0001æ1370æ 36ææææô
Si prega di inviare un esempio del tutto il file in modo che altri possano ripetere l'errore. –
Lavorando su di esso. Cercando di ridurlo a qualcosa che le persone possono effettivamente eseguire (il codice reale si lega a molte altre cose per ottenere i suoi dati). Finora, però, nessuno dei miei tagli ha causato l'errore, anche se tutto ciò che ho fatto è davvero scambiare le fonti di dati con dati statici nel codice. Hmmmmm ... –
Ok, tutto il codice pubblicato. Spero possa aiutare. Ha fatto un po 'di debug in profondità, ma tutto ciò che ha fatto è mostrarmi come sta succedendo il problema, non quello che posso fare al riguardo. –