ReportLab LayoutError: слишком большой на странице

Я делаю свою первую программу с помощью ReportLab, где я не знаю заранее, когда разрывы страницы упадут, и у меня возникнут проблемы. Чтобы все было просто, я использую SimpleDocTemplate. Мои потоки выглядят примерно так:

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(),
             ...]

Когда я строю свой PDF файл, все идет хорошо, пока мои n или m или хотя бы несколько абзацев тела подходят на одной странице, но если они будут работать, я получаю следующее сообщение:

reportlab.platypus.doctemplate.LayoutError: Flowable <Paragraph at 0xb79800 frame=normal>20th paragraph: too large on page 3

Кажется, не может найти вескую причину, почему это происходит со мной. Какие-либо предложения? Он делает это, даже если я удаляю PageBreaks(). Все абзацы относительно короткие, в основном меньше одного предложения/строки.

ETA: Я отправляю весь код (с незначительными идентификаторами), который генерирует ошибку для меня. Я конвертировал его для чтения CSV файла, поэтому я также разместил его содержимое. Точная ошибка, которую генерирует этот код для меня при запуске:

Traceback (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

Некоторая работа по отладке показывает, что ошибка является результатом этого абзаца (хотя это может быть и другие текущие потоки, в зависимости от длины содержимого), пытающиеся разбить, откладываться и затем все еще не могут быть разделены после вызова handle_frameEnd(). Предложения?

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('&','&amp;').replace('<','&lt;').replace('>','&gt;')

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 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 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ææææô

Ответ 1

Обнаружен обходной путь. Основываясь на некоторых изменениях кода, сделанных в rst2pdf, я смог надежно защитить свой код. Решение, хотя и уродливое, состоит в том, чтобы обернуть весь мой Paragraphs в разделе кода, который создает Paragraphs для комментариев ученика внутри KeepTogether. Например, я изменил одну соответствующую строку на:

reportDocContent.append(KeepTogether(Paragraph(commentParagraph, style=commentParagraphStyle)))

и теперь он работает (по крайней мере, я еще не смог его сломать, попробовав множество выборочных данных).

Ответ 2

Похоже, что это старый вопрос, но я очень недавно испытал эту ошибку, и пришел сюда, чтобы найти некоторые советы. Исправление, которое я сделал, состояло в том, чтобы размер проставки составлял половину старого размера. Это был ранее Spacer (1,0,2 дюйма), и я изменил его на Spacer (1,0,1 * дюйма). Тогда таких ошибок больше нет.

FYI сообщение об ошибке, которое я получил, было

  File "/opt/python2.7/lib/python2.7/site-packages/reportlab-2.5-py2.7-linux-x86_64.egg/reportlab/platypus/doctemplate.py", line 1117, in build
    BaseDocTemplate.build(self,flowables, canvasmaker=canvasmaker)
  File "/opt/python2.7/lib/python2.7/site-packages/reportlab-2.5-py2.7-linux-x86_64.egg/reportlab/platypus/doctemplate.py", line 880, in build
    self.handle_flowable(flowables)
  File "/opt/python2.7/lib/python2.7/site-packages/reportlab-2.5-py2.7-linux-x86_64.egg/reportlab/platypus/doctemplate.py", line 793, in handle_flowable
    raise LayoutError(ident)
reportlab.platypus.doctemplate.LayoutError: Flowable <Spacer at 0xf01440 frame=normal>...(1 x 14.4) too large on page 10 in frame 'normal'(439.275590551 x 628.28976378) of template 'Later'