--- a/src/reportlab/__init__.py Thu Apr 25 09:28:47 2019 +0100
+++ b/src/reportlab/__init__.py Thu Apr 25 09:29:41 2019 +0100
@@ -1,9 +1,9 @@
#Copyright ReportLab Europe Ltd. 2000-2018
#see license.txt for license details
__doc__="""The Reportlab PDF generation library."""
-Version = "3.5.19"
+Version = "3.5.20"
__version__=Version
-__date__='20190415'
+__date__='20190425'
import sys, os
--- a/src/reportlab/platypus/__init__.py Thu Apr 25 09:28:47 2019 +0100
+++ b/src/reportlab/platypus/__init__.py Thu Apr 25 09:29:41 2019 +0100
@@ -1,15 +1,14 @@
#Copyright ReportLab Europe Ltd. 2000-2017
#see license.txt for license details
#history https://bitbucket.org/rptlab/reportlab/history-node/tip/src/reportlab/platypus/__init__.py
-__version__='3.3.0'
+__version__='3.5.20'
__doc__='''Page Layout and Typography Using Scripts" - higher-level framework for flowing documents'''
from .flowables import *
from .frames import *
-from reportlab.platypus.paragraph import Paragraph, cleanBlockQuotedText, ParaLines
-from reportlab.platypus.paraparser import ParaFrag
-from reportlab.platypus.tables import Table, TableStyle, CellStyle, LongTable
-from reportlab.platypus.doctemplate import BaseDocTemplate, NextPageTemplate, PageTemplate, ActionFlowable, \
- SimpleDocTemplate, FrameBreak, PageBegin, Indenter, NotAtTopPageBreak, \
- NullActionFlowable, IndexingFlowable
-from reportlab.platypus.xpreformatted import XPreformatted
+from .multicol import *
+from .paragraph import *
+from .paraparser import *
+from .tables import *
+from .doctemplate import *
+from .xpreformatted import *
--- a/src/reportlab/platypus/doctemplate.py Thu Apr 25 09:28:47 2019 +0100
+++ b/src/reportlab/platypus/doctemplate.py Thu Apr 25 09:29:41 2019 +0100
@@ -1,8 +1,26 @@
#Copyright ReportLab Europe Ltd. 2000-2017
#see license.txt for license details
#history https://bitbucket.org/rptlab/reportlab/history-node/tip/src/reportlab/platypus/doctemplate.py
-
-__version__='3.4.2'
+__all__ = (
+ 'ActionFlowable',
+ 'BaseDocTemplate',
+ 'CurrentFrameFlowable',
+ 'FrameActionFlowable',
+ 'FrameBreak',
+ 'Indenter',
+ 'IndexingFlowable',
+ 'LayoutError',
+ 'LCActionFlowable',
+ 'NextFrameFlowable',
+ 'NextPageTemplate',
+ 'NotAtTopPageBreak',
+ 'NullActionFlowable',
+ 'PageAccumulator',
+ 'PageBegin',
+ 'PageTemplate',
+ 'SimpleDocTemplate',
+ )
+__version__='3.5.20'
__doc__="""
This module contains the core structure of platypus.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/reportlab/platypus/multicol.py Thu Apr 25 09:29:41 2019 +0100
@@ -0,0 +1,111 @@
+__all__ = '''MultiCol'''.split()
+from reportlab.lib.utils import strTypes
+from .flowables import Flowable, _Container, _FindSplitterMixin, _listWrapOn
+
+class MultiCol(_Container,_FindSplitterMixin,Flowable):
+ def __init__(self,contents,widths, minHeightNeeded=36, spaceBefore=None, spaceAfter=None):
+ if len(contents)!=len(widths):
+ raise ValueError('%r len(contents)=%d not the same as len(widths)=%d' % (self,len(contents),len(widths)))
+ self.contents = contents
+ self.widths = widths
+ self.minHeightNeeded = minHeightNeeded
+ self._spaceBefore = spaceBefore
+ self._spaceAfter = spaceAfter
+ self._naW = None
+
+ def nWidths(self,aW):
+ if aW==self._naW: return self._nW
+ nW = [].append
+ widths = self.widths
+ s = 0.0
+ for i,w in enumerate(widths):
+ if isinstance(w,strTypes):
+ w=w.strip()
+ pc = w.endswith('%')
+ if pc: w=w[:-1]
+ try:
+ w = float(w)
+ except:
+ raise ValueError('%s: nWidths failed with value %r' % (self,widths[i]))
+ if pc: w = w*0.01*aW
+ elif not isinstance(w,(float,int)):
+ raise ValueError('%s: nWidths failed with value %r' % (self,widths[i]))
+
+ s += w
+ nW(w)
+
+ self._naW = aW
+ s = aW / s
+ self._nW = [w*s for w in nW.__self__]
+ return self._nW
+
+ def wrap(self,aW,aH):
+ widths = self.nWidths(aW)
+ w = h = 0.0
+ canv = self.canv
+ h = 0
+ for faW,F in zip(widths,self.contents):
+ if not F:
+ fW = faW
+ fH = 0
+ else:
+ fW,fH = _listWrapOn(F,faW,canv)
+ h = max(h,fH)
+ w += fW
+ self.width = w
+ self.height = h
+ return w, h
+
+ def split(self,aW,aH):
+ if aH<self.minHeightNeeded:
+ return []
+ widths = self.nWidths(aW)
+ S = [[],[]]
+ canv = self.canv
+ for faW,F in zip(widths,self.contents):
+ if not F:
+ fW = faW
+ fH0 = 0
+ S0 = []
+ S1 = []
+ else:
+ fW,fH0,S0,S1 = self._findSplit(canv,faW,aH,content=F,paraFix=False)
+ if S0 is F: return [] #we failed to find a split
+ S[0].append(S0)
+ S[1].append(S1)
+
+ return [
+ MultiCol(S[0],
+ self.widths,
+ minHeightNeeded=self.minHeightNeeded,
+ spaceBefore=self._spaceBefore,
+ spaceAfter=self._spaceAfter),
+ MultiCol(S[1],
+ self.widths,
+ minHeightNeeded=self.minHeightNeeded,
+ spaceBefore=self._spaceBefore,
+ spaceAfter=self._spaceAfter),
+ ]
+
+ def getSpaceAfter(self):
+ m = self._spaceAfter
+ if m is None:
+ m = 0
+ for F in self.contents:
+ m = max(m,_Container.getSpaceAfter(self,F))
+ return m
+
+ def getSpaceBefore(self):
+ m = self._spaceBefore
+ if m is None:
+ m = 0
+ for F in self.contents:
+ m = max(m,_Container.getSpaceBefore(self,F))
+ return m
+
+ def drawOn(self, canv, x, y, _sW=0):
+ widths = self._nW
+ xOffs = 0
+ for faW,F in zip(widths,self.contents):
+ _Container.drawOn(self, canv, x+xOffs, y, content=F, aW=faW)
+ xOffs += faW
--- a/src/reportlab/platypus/paragraph.py Thu Apr 25 09:28:47 2019 +0100
+++ b/src/reportlab/platypus/paragraph.py Thu Apr 25 09:29:41 2019 +0100
@@ -1,7 +1,13 @@
#Copyright ReportLab Europe Ltd. 2000-2017
#see license.txt for license details
#history https://bitbucket.org/rptlab/reportlab/history-node/tip/src/reportlab/platypus/paragraph.py
-__version__='3.3.0'
+__all__=(
+ 'Paragraph',
+ 'cleanBlockQuotedText',
+ 'ParaLines',
+ 'FragLine',
+ )
+__version__='3.5.20'
__doc__='''The standard paragraph implementation'''
from string import whitespace
from operator import truth
--- a/src/reportlab/platypus/paraparser.py Thu Apr 25 09:28:47 2019 +0100
+++ b/src/reportlab/platypus/paraparser.py Thu Apr 25 09:29:41 2019 +0100
@@ -1,7 +1,8 @@
#Copyright ReportLab Europe Ltd. 2000-2017
#see license.txt for license details
#history https://bitbucket.org/rptlab/reportlab/history-node/tip/src/reportlab/platypus/paraparser.py
-__version__='3.3.0'
+__all__ = ('ParaFrag', 'ParaParser')
+__version__='3.5.20'
__doc__='''The parser used to process markup within paragraphs'''
import string
import re
--- a/src/reportlab/platypus/tables.py Thu Apr 25 09:28:47 2019 +0100
+++ b/src/reportlab/platypus/tables.py Thu Apr 25 09:29:41 2019 +0100
@@ -1,7 +1,13 @@
#Copyright ReportLab Europe Ltd. 2000-2017
#see license.txt for license details
#history https://bitbucket.org/rptlab/reportlab/history-node/tip/src/reportlab/platypus/tables.py
-__version__='3.3.0'
+__all__= (
+ 'Table',
+ 'TableStyle',
+ 'CellStyle',
+ 'LongTable',
+ )
+__version__='3.5.20'
__doc__="""
Tables are created by passing the constructor a tuple of column widths, a tuple of row heights and the data in
--- a/src/reportlab/platypus/xpreformatted.py Thu Apr 25 09:28:47 2019 +0100
+++ b/src/reportlab/platypus/xpreformatted.py Thu Apr 25 09:29:41 2019 +0100
@@ -1,7 +1,11 @@
#Copyright ReportLab Europe Ltd. 2000-2017
#see license.txt for license details
#history https://bitbucket.org/rptlab/reportlab/history-node/tip/src/reportlab/platypus/xpreformatted.py
-__version__='3.3.0'
+__all__ = (
+ 'XPreformatted',
+ 'PythonPreformatted',
+ )
+__version__='3.5.20'
__doc__='''A 'rich preformatted text' widget allowing internal markup'''
from reportlab.lib import PyFontify
from reportlab.platypus.paragraph import Paragraph, cleanBlockQuotedText, _handleBulletWidth, \
--- a/tests/test_platypus_lists.py Thu Apr 25 09:28:47 2019 +0100
+++ b/tests/test_platypus_lists.py Thu Apr 25 09:29:41 2019 +0100
@@ -1,12 +1,16 @@
from random import randint
+from xml.sax.saxutils import escape as xmlEscape
+from reportlab import xrange
from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, printLocation
setOutDir(__name__)
import os,unittest
-from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, ListFlowable, ListItem, Paragraph, PageBreak
+from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, ListFlowable, ListItem, \
+ Paragraph, PageBreak, DDIndenter, MultiCol
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch, cm
from reportlab.lib.utils import simpleSplit
from reportlab.lib import colors
+from reportlab.lib import randomtext
TEXTS=[
'''We have already seen that the notion of level of grammaticalness is,
@@ -57,15 +61,16 @@
def test1(self):
styleSheet = getSampleStyleSheet()
- doc = SimpleDocTemplate(outputfile('test_platypus_lists1.pdf'))
+ doc = SimpleDocTemplate(outputfile('test_platypus_lists1.pdf'),showBoundary=True)
story=[]
sty = [ ('GRID',(0,0),(-1,-1),1,colors.green),
('BOX',(0,0),(-1,-1),2,colors.red),
]
normal = styleSheet['BodyText']
+ bold = normal.clone('bold',fontName='Helvetica-Bold')
lpSty = normal.clone('lpSty',spaceAfter=18)
- data = [[str(i+1), Paragraph("xx "* (i%10), styleSheet["BodyText"]), Paragraph(("blah "*(i%40)), normal)] for i in range(5)]
- data1 = [[str(i+1), Paragraph(["zz ","yy "][i]*(i+3), styleSheet["BodyText"]), Paragraph(("duh "*(i+3)), normal)] for i in range(2)]
+ data = [[str(i+1), Paragraph("xx "* (i%10), styleSheet["BodyText"]), Paragraph(("blah "*(i%40)), normal)] for i in xrange(5)]
+ data1 = [[str(i+1), Paragraph(["zz ","yy "][i]*(i+3), styleSheet["BodyText"]), Paragraph(("duh "*(i+3)), normal)] for i in xrange(2)]
OL = ListFlowable(
[
Paragraph("A table with 5 rows", lpSty),
@@ -157,7 +162,45 @@
),
)
-
+ story.append(PageBreak())
+ story.append(Paragraph("DDIndenter", style=normal))
+ story.append(Paragraph("Coffee",style=bold))
+ story.append(DDIndenter(Paragraph("Black hot drink",style=normal),leftIndent=36))
+ story.append(Paragraph("Milk",style=bold))
+ story.append(DDIndenter(Paragraph("White cold drink",style=normal),leftIndent=36))
+ story.append(Paragraph("Whiskey",style=bold))
+ story.append(DDIndenter(Paragraph("A nice alcoholic drink",style=normal),leftIndent=36))
+ story.append(PageBreak())
+ story.append(Paragraph("MultiCol", style=normal))
+ RT = 'STARTUP COMPUTERS BLAH BUZZWORD STARTREK PRINTING PYTHON CHOMSKY CHOMSKY'.split()
+ for i in xrange(5):
+ topic = RT[randint(0,len(RT)-1)]
+ np = randint(2,6)
+ story.append(
+ MultiCol([
+ [Paragraph('Column %d' % (i+1,),style=bold)],
+ [],
+ [Paragraph(xmlEscape(randomtext.randomText(topic,randint(1,7))),style=normal) for j in xrange(np)]
+ ],
+ widths=['20%',3,'80%'],
+ )
+ )
+
+ story.append(PageBreak())
+ story.append(Paragraph("MultiCol 2", style=normal))
+ for i in xrange(5):
+ topic = RT[randint(0,len(RT)-1)]
+ np = randint(2,6)
+ story.append(
+ MultiCol([
+ ([Paragraph('Column %d' % (i+1,),style=bold)]+
+ [Paragraph(xmlEscape(randomtext.randomText(topic,randint(1,7))),style=normal) for j in xrange(np)]),
+ [],
+ [Paragraph(xmlEscape(randomtext.randomText(topic,randint(1,7))),style=normal) for j in xrange(np)]
+ ],
+ widths=['50%',5,'50%'],
+ )
+ )
doc.build(story)