Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-reportlab for 
openSUSE:Factory checked in at 2021-01-15 19:44:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-reportlab (Old)
 and      /work/SRC/openSUSE:Factory/.python-reportlab.new.28504 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-reportlab"

Fri Jan 15 19:44:31 2021 rev:29 rq:862304 version:3.5.59

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-reportlab/python-reportlab.changes        
2020-12-12 20:32:07.253836799 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-reportlab.new.28504/python-reportlab.changes 
    2021-01-15 19:44:47.405893354 +0100
@@ -1,0 +2,17 @@
+Mon Jan 11 12:31:13 UTC 2021 - Antonio Larrosa <alarr...@suse.com>
+
+- Update to 3.5.59
+  * Allow variant corners in Canvas.roundRect
+  * Allow tables to have rounded corners
+- Update to 3.5.58
+  * added ddfStyle to Label
+  * allowed for embedded(and ordinary)Hyphenation to pre-empt splitting when 
embeddedHyphenation>=2
+  * fix extension escapePDF so it can handle unicode
+  * fix poundsign in Ean5BarcodeWidget
+  * Table can use __styledWrap__ for sizing
+  * test fixes so 3.9 and 2.7 produce same pdf
+- Update to 3.5.57
+  * added .github action wheel.yml
+  * micro change to userguide doc
+
+-------------------------------------------------------------------

Old:
----
  reportlab-3.5.56.tar.gz

New:
----
  reportlab-3.5.59.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-reportlab.spec ++++++
--- /var/tmp/diff_new_pack.vq6OvA/_old  2021-01-15 19:44:48.217894562 +0100
+++ /var/tmp/diff_new_pack.vq6OvA/_new  2021-01-15 19:44:48.221894568 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-reportlab
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define oldpython python
 Name:           python-reportlab
-Version:        3.5.56
+Version:        3.5.59
 Release:        0
 Summary:        The Reportlab Toolkit
 License:        BSD-3-Clause


++++++ reportlab-3.5.56.tar.gz -> reportlab-3.5.59.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/CHANGES.md 
new/reportlab-3.5.59/CHANGES.md
--- old/reportlab-3.5.56/CHANGES.md     2020-12-01 17:29:04.000000000 +0100
+++ new/reportlab-3.5.59/CHANGES.md     2021-01-01 19:09:10.000000000 +0100
@@ -11,6 +11,25 @@
 The contributors lists are in no order and apologies to those accidentally not
 mentioned. If we missed you, please let us know!
 
+CHANGES  3.5.58         01/01/2021
+---------------------------
+       * Allow variant corners in Canvas.roundRect
+       * Allow tables to have rounded corners
+
+CHANGES  3.5.57         27/12/2020
+---------------------------
+       * added ddfStyle to Label
+       * allowed for embedded(and ordinary)Hyphenation to pre-empt splitting 
when embeddedHyphenation>=2
+       * fix extension escapePDF so it can handle unicode
+       * fix poundsign in Ean5BarcodeWidget
+       * Table can use __styledWrap__ for sizing
+       * test fixes so 3.9 and 2.7 produce same pdf
+
+CHANGES  3.5.56         10/12/2020
+---------------------------
+       * added .github action wheel.yml
+       * micro change to userguide doc
+
 RELEASE 3.5.56  01/12/2020
 ---------------------------
        * micro changes for Big Sur in C extensions
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/PKG-INFO 
new/reportlab-3.5.59/PKG-INFO
--- old/reportlab-3.5.56/PKG-INFO       2020-12-01 17:29:31.000000000 +0100
+++ new/reportlab-3.5.59/PKG-INFO       2021-01-04 15:52:21.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: reportlab
-Version: 3.5.56
+Version: 3.5.59
 Summary: The Reportlab Toolkit
 Home-page: http://www.reportlab.com/
 Author: Andy Robinson, Robin Becker, the ReportLab team and the community
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/docs/userguide/ch5_paragraphs.py 
new/reportlab-3.5.59/docs/userguide/ch5_paragraphs.py
--- old/reportlab-3.5.56/docs/userguide/ch5_paragraphs.py       2020-12-01 
17:29:04.000000000 +0100
+++ new/reportlab-3.5.59/docs/userguide/ch5_paragraphs.py       2020-12-27 
12:44:36.000000000 +0100
@@ -345,7 +345,7 @@
 This &lt;img/&gt; <img src="../images/testimg.gif" width="10"/> has width 
<b>10</b>.<br/><br/>
 </para>""","Inline images")
 disc("""The $src$ attribute can refer to a remote location eg 
$src="https://www.reportlab.com/images/logo.gif"$. By default we set 
$rl_config.trustedShemes$ to $['https','http', 'file', 'data', 'ftp']$ and
-$rl_config.trustedHosts=None$ the latter meaning no-restriction. You can 
modify these variables using one of the override files eg 
$reportlab_settings.py$ or $~/.reportlab_settings$. Or as comma seprated 
strings in the 
+$rl_config.trustedHosts=None$ the latter meaning no-restriction. You can 
modify these variables using one of the override files eg 
$reportlab_settings.py$ or $~/.reportlab_settings$. Or as comma separated 
strings in the 
 environment variables $RL_trustedSchemes$ &amp; $RL_trustedHosts$. Note that 
the $trustedHosts$ values may contain <b>glob</b> wild cars so 
<i>*.reportlab.com</i> will match the obvious domains.
 <br/><span color="red"><b>*NB*</b></span> use of <i>trustedHosts</i> and or 
<i>trustedSchemes</i> may not control behaviour &amp; actions when $URI$ 
patterns
 are detected by the viewer application.""")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/docs/userguide/ch6_tables.py 
new/reportlab-3.5.59/docs/userguide/ch6_tables.py
--- old/reportlab-3.5.56/docs/userguide/ch6_tables.py   2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/docs/userguide/ch6_tables.py   2021-01-04 
15:51:54.000000000 +0100
@@ -57,7 +57,7 @@
 disc("""These are the main methods which are of interest to the client 
programmer.""")
 
 heading4("""$Table(data, colWidths=None, rowHeights=None, style=None, 
splitByRow=1,
-repeatRows=0, repeatCols=0, rowSplitRange=None, spaceBefore=None, 
spaceAfter=None)$""")
+repeatRows=0, repeatCols=0, rowSplitRange=None, spaceBefore=None, 
spaceAfter=None, cornerRadii=None)$""")
 
 disc("""The $data$ argument is a sequence of sequences of cell values each of 
which
 should be convertible to a string value using the $str$ function or should be 
a Flowable instance (such as a $Paragraph$) or a list (or tuple) of such 
instances.
@@ -91,8 +91,11 @@
 that should be repeated when the $Table$ is asked to split itself. If it is a 
tuple it should specify which of the leading rows should be repeated; this 
allows
 for cases where the first appearance of the table hsa more leading rows than 
later split parts.
 The $repeatCols$ argument is currently ignored as a $Table$ cannot be split by 
column.""")
-disc("""The $spaceBefore$ &amp; $spaceAfter$ arguments may be used to put 
extra space before or after the table when renedered in a $platypus$ story.""")
 disc("""The $rowSplitRange$ argument may be used to control the splitting of 
the table to a subset of its rows; that can be to prevent splitting too close 
to the beginning or end of the table.""")
+disc("""The $spaceBefore$ &amp; $spaceAfter$ arguments may be used to put 
extra space before or after the table when renedered in a $platypus$ story.""")
+disc("""The $style$ argument can be an initial style for the table.""")
+disc("""The $cornerRadii$ argument can be a list of the top left, top right, 
bottom left and bottom right radii.
+A positive non-zero radius indicates that the corner should be rounded. This 
argument will override any $ROUNDEDCORNERS$ command in the argument $style$ 
list (ie it has pririty).""")
 heading4('$Table.setStyle(tblStyle)$')
 disc("""
 This method applies a particular instance of class $TableStyle$ (discussed 
below)
@@ -340,6 +343,17 @@
 """)
 disc("""demands that the cells in columns $sc$ - $ec$ and rows $sr$ - $er$ may 
not be split.""")
 
+eg("")
+eg("")
+disc("""To control $Table$ corner rounding the $ROUNDEDCORNERS$ command may be 
used
+The style specification
+""")
+eg("""
+ROUNDEDCORNERS, [tl, tr, bl, br]
+""")
+disc("""specifies the radii of the top left, top right, bottom left and bottom 
right. A value of $0$ indicates a square corner. replace the whole array by 
$None$ to turn off all rounding.
+<br/>Borders at a rounded corner are curved by an octant.""")
+
 heading3("""Special $TableStyle$ Indeces""")
 disc("""In any style command the first row index may be set to one of the 
special strings
 $'splitlast'$ or $'splitfirst'$ to indicate that the style should be used only 
for the last row of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/src/reportlab/__init__.py 
new/reportlab-3.5.59/src/reportlab/__init__.py
--- old/reportlab-3.5.56/src/reportlab/__init__.py      2020-12-01 
17:29:04.000000000 +0100
+++ new/reportlab-3.5.59/src/reportlab/__init__.py      2021-01-04 
15:51:54.000000000 +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.56"
+Version = "3.5.59"
 __version__=Version
-__date__='20201201'
+__date__='20210104'
 
 import sys, os
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/reportlab-3.5.56/src/reportlab/graphics/barcode/eanbc.py 
new/reportlab-3.5.59/src/reportlab/graphics/barcode/eanbc.py
--- old/reportlab-3.5.56/src/reportlab/graphics/barcode/eanbc.py        
2019-10-01 17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/src/reportlab/graphics/barcode/eanbc.py        
2020-12-27 12:44:36.000000000 +0100
@@ -461,7 +461,7 @@
             if s[0] in '3456':
                 price = '$'
             elif s[0] in '01':
-                price = '\xc2\xa3'
+                price = asNative(b'\xc2\xa3')
 
             if price is None:
                 return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/reportlab-3.5.56/src/reportlab/graphics/charts/textlabels.py 
new/reportlab-3.5.59/src/reportlab/graphics/charts/textlabels.py
--- old/reportlab-3.5.56/src/reportlab/graphics/charts/textlabels.py    
2020-01-22 15:40:54.000000000 +0100
+++ new/reportlab-3.5.59/src/reportlab/graphics/charts/textlabels.py    
2020-12-27 12:44:36.000000000 +0100
@@ -16,7 +16,7 @@
 from reportlab.graphics.widgetbase import Widget, PropHolder
 from reportlab.graphics.shapes import _baseGFontName, DirectDraw
 from reportlab.platypus import XPreformatted, Paragraph, Flowable
-from reportlab.lib.styles import ParagraphStyle
+from reportlab.lib.styles import ParagraphStyle, PropertySet
 from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER
 _ta2al = dict(start=TA_LEFT,end=TA_RIGHT,middle=TA_CENTER)
 
@@ -153,6 +153,7 @@
         customDrawChanger = AttrMapValue(isNoneOrCallable,desc="An instance of 
CustomDrawChanger to modify the behavior at draw time", _advancedUsage=1),
         ddf = 
AttrMapValue(NoneOr(isSubclassOf(DirectDraw),'NoneOrDirectDraw'),desc="A 
DirectDrawFlowable instance", _advancedUsage=1),
         ddfKlass = 
AttrMapValue(NoneOr(isSubclassOf(Flowable),'NoneOrDirectDraw'),desc="A 
DirectDrawFlowable instance", _advancedUsage=1),
+        ddfStyle = AttrMapValue(NoneOr(isSubclassOf(PropertySet)),desc="A 
style for a ddfKlass or None", _advancedUsage=1),
         )
 
     def __init__(self,**kw):
@@ -187,6 +188,7 @@
                 useAscentDescent = False,
                 ddf = DirectDrawFlowable,
                 ddfKlass = None,
+                ddfStyle = None,
                 )
 
     def setText(self, text):
@@ -288,12 +290,14 @@
         else:
             if self.ddf is None:
                 raise RuntimeError('DirectDrawFlowable class is not available 
you need the rlextra package as well as reportlab')
-            sty = self._style = ParagraphStyle('xlabel-generated',
+            sty = dict(
+                    name='xlabel-generated',
                     fontName=self.fontName,
                     fontSize=self.fontSize,
                     fillColor=self.fillColor,
                     strokeColor=self.strokeColor,
                     )
+            sty = self._style =  (ddfStyle.clone if self.ddfStyle else 
ParagraphStyle)(**sty)
             self._getBaseLineRatio()
             if self.useAscentDescent:
                 sty.autoLeading = True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/src/reportlab/lib/utils.py 
new/reportlab-3.5.59/src/reportlab/lib/utils.py
--- old/reportlab-3.5.56/src/reportlab/lib/utils.py     2020-10-29 
13:35:05.000000000 +0100
+++ new/reportlab-3.5.59/src/reportlab/lib/utils.py     2021-01-04 
15:51:54.000000000 +0100
@@ -16,6 +16,16 @@
 from reportlab.lib.rltempfile import get_rl_tempfile, get_rl_tempdir, 
_rl_getuid
 from . rl_safe_eval import rl_safe_exec, rl_safe_eval, safer_globals
 
+class __UNSET__(object):
+    @staticmethod
+    def __bool__():
+        return False
+    @staticmethod
+    def __str__():
+        return '__UNSET__'
+    __repr__ = __str__
+__UNSET__ = __UNSET__()
+
 try:
     import cPickle as pickle
 except ImportError:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/src/reportlab/pdfgen/canvas.py 
new/reportlab-3.5.59/src/reportlab/pdfgen/canvas.py
--- old/reportlab-3.5.56/src/reportlab/pdfgen/canvas.py 2020-10-02 
17:51:34.000000000 +0200
+++ new/reportlab-3.5.59/src/reportlab/pdfgen/canvas.py 2020-12-27 
12:44:36.000000000 +0100
@@ -23,7 +23,7 @@
 from reportlab.pdfgen  import pdfgeom, pathobject
 from reportlab.pdfgen.textobject import PDFTextObject, _PDFColorSetter
 from reportlab.lib.colors import black, _chooseEnforceColorSpace, Color, 
CMYKColor, toColor
-from reportlab.lib.utils import import_zlib, ImageReader, isSeq, isStr, 
isUnicode, _digester
+from reportlab.lib.utils import import_zlib, ImageReader, isSeq, isStr, 
isUnicode, _digester, asUnicode
 from reportlab.lib.rl_accel import fp_str, escapePDF
 from reportlab.lib.boxstuff import aspectRatioFix
 
@@ -1595,8 +1595,7 @@
 
     def drawString(self, x, y, text, mode=None, charSpace=0, direction=None, 
wordSpace=None):
         """Draws a string in the current text styles."""
-        if sys.version_info[0] == 3 and not isinstance(text, str):
-            text = text.decode('utf-8')
+        text = asUnicode(text)
         #we could inline this for speed if needed
         t = self.beginText(x, y, direction=direction)
         if mode is not None: t.setTextRenderMode(mode)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/src/reportlab/pdfgen/pathobject.py 
new/reportlab-3.5.59/src/reportlab/pdfgen/pathobject.py
--- old/reportlab-3.5.56/src/reportlab/pdfgen/pathobject.py     2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/src/reportlab/pdfgen/pathobject.py     2021-01-01 
19:09:10.000000000 +0100
@@ -25,7 +25,7 @@
 
     Path objects are probably not long, so we pack onto one line
 
-    the code argument allows a canvas to get the operatiosn appended directly 
so
+    the code argument allows a canvas to get the operations appended directly 
so
     avoiding the final getCode
     """
     def __init__(self,code=None):
@@ -95,31 +95,43 @@
         #use a precomputed set of factors for the bezier approximation
         #to a circle. There are six relevant points on the x axis and y axis.
         #sketch them and it should all make sense!
-        t = 0.4472 * radius
-
-        x0 = x
-        x1 = x0 + t
-        x2 = x0 + radius
-        x3 = x0 + width - radius
-        x4 = x0 + width - t
-        x5 = x0 + width
-
-        y0 = y
-        y1 = y0 + t
-        y2 = y0 + radius
-        y3 = y0 + height - radius
-        y4 = y0 + height - t
-        y5 = y0 + height
-
-        self.moveTo(x2, y0)
-        self.lineTo(x3, y0) #bottom row
-        self.curveTo(x4, y0, x5, y1, x5, y2) #bottom right
-        self.lineTo(x5, y3) #right edge
-        self.curveTo(x5, y4, x4, y5, x3, y5) #top right
-        self.lineTo(x2, y5) #top row
-        self.curveTo(x1, y5, x0, y4, x0, y3) #top left
-        self.lineTo(x0, y2) #left edge
-        self.curveTo(x0, y1, x1, y0, x2, y0) #bottom left
+        m = 0.4472  #radius multiplier
+        xhi = x,x+width
+        xlo, xhi = min(xhi), max(xhi)
+        yhi = y,y+height
+        ylo, yhi = min(yhi), max(yhi)
+        if isinstance(radius,(list,tuple)):
+            r = [max(0,r) for r in radius]
+            if len(r)<4: r += (4-len(r))*[0]
+            self.moveTo(xlo + r[2], ylo)    #start at bottom left
+            self.lineTo(xhi - r[3], ylo)    #bottom row
+            if r[3]>0:
+                t = m*r[3]
+                self.curveTo(xhi - t, ylo, xhi, ylo + t, xhi, ylo + r[3]) 
#bottom right
+            self.lineTo(xhi, yhi - r[1]) #right edge
+            if r[1]>0:
+                t = m*r[1]
+                self.curveTo(xhi, yhi - t, xhi - t, yhi, xhi - r[1], yhi) #top 
right
+            self.lineTo(xlo + r[0], yhi) #top row
+            if r[0]>0:
+                t = m*r[0]
+                self.curveTo(xlo + t, yhi, xlo, yhi - t, xlo, yhi - r[0]) #top 
left
+            self.lineTo(xlo, ylo + r[2]) #left edge
+            if r[2]>0:
+                t = m*r[2]
+                self.curveTo(xlo, ylo + t, xlo + t, ylo, xlo + r[2], ylo) 
#bottom left
+            # 4 radii top left top right bittom left bottom right
+        else:
+            t = m * radius
+            self.moveTo(xlo + radius, ylo)
+            self.lineTo(xhi - radius, ylo) #bottom row
+            self.curveTo(xhi - t, ylo, xhi, ylo + t, xhi, ylo + radius) 
#bottom right
+            self.lineTo(xhi, yhi - radius) #right edge
+            self.curveTo(xhi, yhi - t, xhi - t, yhi, xhi - radius, yhi) #top 
right
+            self.lineTo(xlo + radius, yhi) #top row
+            self.curveTo(xlo + t, yhi, xlo, yhi - t, xlo, yhi - radius) #top 
left
+            self.lineTo(xlo, ylo + radius) #left edge
+            self.curveTo(xlo, ylo + t, xlo + t, ylo, xlo + radius, ylo) 
#bottom left
         self.close()
 
     def close(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/src/reportlab/platypus/paragraph.py 
new/reportlab-3.5.59/src/reportlab/platypus/paragraph.py
--- old/reportlab-3.5.56/src/reportlab/platypus/paragraph.py    2020-07-20 
09:39:52.000000000 +0200
+++ new/reportlab-3.5.59/src/reportlab/platypus/paragraph.py    2020-12-27 
12:44:36.000000000 +0100
@@ -2014,6 +2014,7 @@
             hyphenator = None
         uriWasteReduce = style.uriWasteReduce
         embeddedHyphenation = style.embeddedHyphenation
+        hyphenation2 = embeddedHyphenation>1
         spaceShrinkage = style.spaceShrinkage
         splitLongWords = style.splitLongWords
         attemptHyphenation = hyphenator or uriWasteReduce or 
embeddedHyphenation
@@ -2078,6 +2079,17 @@
                             self._hyphenations += 1
                             forcedSplit = 1
                             continue
+                        elif hyphenation2 and len(cLine):
+                            hsw = word.__shysplit__(
+                                fontName, fontSize,
+                                0 + hyw - 1e-8,
+                                maxWidth,
+                                encoding = self.encoding,
+                                )
+                            if hsw:
+                                words[0:0] = [word]
+                                forcedSplit = 1
+                                word = None
                     elif attemptHyphenation:
                         hyOk = not getattr(f,'nobr',False)
                         hsw = _hyphenateWord(hyphenator if hyOk else None,
@@ -2089,7 +2101,16 @@
                             self._hyphenations += 1
                             forcedSplit = 1
                             continue
-                    if splitLongWords and not isinstance(word,_SplitWord):
+                        elif hyphenation2 and len(cLine):
+                            hsw = _hyphenateWord(hyphenator if hyOk else None,
+                                fontName, fontSize, word, wordWidth, 
wordWidth, maxWidth,
+                                    uriWasteReduce if hyOk else False,
+                                    embeddedHyphenation and hyOk, hymwl)
+                            if hsw:
+                                words[0:0] = [word]
+                                forcedSplit = 1
+                                word = None
+                    if splitLongWords and not (isinstance(word,_SplitWord) or 
forcedSplit):
                         nmw = min(lineno,maxlineno)
                         if wordWidth>max(maxWidths[nmw:nmw+1]):
                             #a long word
@@ -2099,7 +2120,7 @@
                             continue
                 if newWidth <= (maxWidth+spaceShrink) or not len(cLine) or 
forcedSplit:
                     # fit one more on this line
-                    cLine.append(word)
+                    if word: cLine.append(word)
                     if forcedSplit:
                         forcedSplit = 0
                         if newWidth > self._width_max: self._width_max = 
newWidth
@@ -2170,6 +2191,13 @@
                             FW.pop(-1)  #remove this as we are doing this one 
again
                             self._hyphenations += 1
                             continue
+                        elif hyphenation2 and len(FW)>1:    #only if we are 
not the first word on the line
+                            hsw = w.shyphenate(wordWidth, maxWidth)
+                            if hsw:
+                                _words[0:0] = 
[_InjectedFrag([0,(f.clone(_fkind=_FK_BREAK,text=''),'')]),w]
+                                FW.pop(-1)  #remove this as we are doing this 
one again
+                                continue
+                        #else: try to split an overlong word
                     elif attemptHyphenation:
                         hyOk = not getattr(f,'nobr',False)
                         hsw = _hyphenateFragWord(hyphenator if hyOk else None,
@@ -2182,6 +2210,16 @@
                             FW.pop(-1)  #remove this as we are doing this one 
again
                             self._hyphenations += 1
                             continue
+                        elif hyphenation2 and len(FW)>1:
+                            hsw = _hyphenateFragWord(hyphenator if hyOk else 
None,
+                                        w,wordWidth,maxWidth,
+                                        uriWasteReduce if hyOk else False,
+                                        embeddedHyphenation and hyOk, hymwl)
+                            if hsw:
+                                _words[0:0] = 
[_InjectedFrag([0,(f.clone(_fkind=_FK_BREAK,text=''),'')]),w]
+                                FW.pop(-1)  #remove this as we are doing this 
one again
+                                continue
+                        #else: try to split an overlong word
                     if splitLongWords and not isinstance(w,_SplitFrag):
                         nmw = min(lineno,maxlineno)
                         if wordWidth>max(maxWidths[nmw:nmw+1]):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/src/reportlab/platypus/tables.py 
new/reportlab-3.5.59/src/reportlab/platypus/tables.py
--- old/reportlab-3.5.56/src/reportlab/platypus/tables.py       2020-08-07 
09:31:22.000000000 +0200
+++ new/reportlab-3.5.59/src/reportlab/platypus/tables.py       2021-01-04 
15:51:54.000000000 +0100
@@ -27,12 +27,14 @@
 from reportlab import rl_config, xrange, ascii
 from reportlab.lib.styles import PropertySet, ParagraphStyle, _baseFontName
 from reportlab.lib import colors
-from reportlab.lib.utils import annotateException, IdentStr, flatten, isStr, 
asNative, strTypes
+from reportlab.lib.utils import annotateException, IdentStr, flatten, isStr, 
asNative, strTypes, __UNSET__
+from reportlab.lib.validators import isListOfNumbersOrNone
 from reportlab.lib.rl_accel import fp_str
 from reportlab.lib.abag import ABag as CellFrame
 from reportlab.pdfbase.pdfmetrics import stringWidth
 from reportlab.platypus.doctemplate import Indenter, NullActionFlowable
 from reportlab.platypus.flowables import LIIndenter
+from collections import namedtuple
 
 LINECAPS={None: None, 'butt':0,'round':1,'projecting':2,'squared':2}
 LINEJOINS={None: None, 'miter':0, 'mitre':0, 'round':1,'bevel':2}
@@ -138,6 +140,41 @@
             R[j] = v
     return R
 
+def _calcBezierPoints(P, kind):
+    '''calculate all or half of a bezier curve
+    kind==0 all, 1=first half else second half''' 
+    if kind==0:
+        return P
+    else:
+        Q0 = (0.5*(P[0][0]+P[1][0]),0.5*(P[0][1]+P[1][1]))
+        Q1 = (0.5*(P[1][0]+P[2][0]),0.5*(P[1][1]+P[2][1]))
+        Q2 = (0.5*(P[2][0]+P[3][0]),0.5*(P[2][1]+P[3][1]))
+        R0 = (0.5*(Q0[0]+Q1[0]),0.5*(Q0[1]+Q1[1]))
+        R1 = (0.5*(Q1[0]+Q2[0]),0.5*(Q1[1]+Q2[1]))
+        S0 = (0.5*(R0[0]+R1[0]),0.5*(R0[1]+R1[1]))
+        return [P[0],Q0,R0,S0] if kind==1 else [S0,R1,Q2,P[3]]
+
+def _quadrantDef(xpos, ypos, corner, r, kind=0, direction='left-right', 
m=0.4472):
+    t = m*r
+    if xpos=='right' and ypos=='bottom': #bottom right
+        xhi,ylo = corner
+        P = [(xhi - r, ylo),(xhi-t, ylo), (xhi, ylo + t), (xhi, ylo + r)]
+    elif xpos=='right' and ypos=='top': #top right
+        xhi,yhi = corner
+        P = [(xhi, yhi - r),(xhi, yhi - t), (xhi - t, yhi), (xhi - r, yhi)]
+    elif xpos=='left' and ypos=='top': #top left
+        xlo,yhi = corner
+        P = [(xlo + r, yhi),(xlo + t, yhi), (xlo, yhi - t), (xlo, yhi - r)]
+    elif xpos=='left' and ypos=='bottom': #bottom left
+        xlo,ylo = corner
+        P = [(xlo, ylo + r),(xlo, ylo + t), (xlo + t, ylo), (xlo + r, ylo)]
+    else:
+        raise ValueError('Unknown quadrant position %s' % repr((xpos,ypos)))
+    if direction=='left-right' and P[0][0]>P[-1][0] or direction=='bottom-top' 
and P[0][1]>P[-1][1]:
+        P.reverse()
+    P = _calcBezierPoints(P, kind)
+    return P
+
 def _hLine(canvLine, scp, ecp, y, hBlocks, FUZZ=rl_config._FUZZ):
     '''
     Draw horizontal lines; do not draw through regions specified in hBlocks
@@ -208,11 +245,17 @@
 class _ExpandedCellTuple(tuple):
     pass
 
+
+RoundingRectDef = namedtuple('RoundingRectDefs','x0 y0 w h x1 y1 ar SL')
+RoundingRectLine = namedtuple('RoundingRectLine','xs ys xe ye weight color cap 
dash join')
+
 class Table(Flowable):
     def __init__(self, data, colWidths=None, rowHeights=None, style=None,
                 repeatRows=0, repeatCols=0, splitByRow=1, 
emptyTableAction=None, ident=None,
                 hAlign=None,vAlign=None, normalizedData=0, cellStyles=None, 
rowSplitRange=None,
-                spaceBefore=None,spaceAfter=None, longTableOptimize=None, 
minRowHeights=None):
+                spaceBefore=None,spaceAfter=None, longTableOptimize=None, 
minRowHeights=None,
+                cornerRadii=__UNSET__, #or [topLeft, topRight, bottomLeft 
bottomRight]
+                ):
         self.ident = ident
         self.hAlign = hAlign or 'CENTER'
         self.vAlign = vAlign or 'MIDDLE'
@@ -297,6 +340,9 @@
         if style:
             self.setStyle(style)
 
+        if cornerRadii is not __UNSET__:    #instance argument overrides
+            self._setCornerRadii(cornerRadii)
+
         self._rowSplitRange = rowSplitRange
         if spaceBefore is not None:
             self.spaceBefore = spaceBefore
@@ -311,6 +357,7 @@
                 minRowHeights = 
minRowHeights+(nrows-lmrh)*minRowHeights.__class__((0,))
         self._minRowHeights = minRowHeights
 
+
     def __repr__(self):
         "incomplete, but better than nothing"
         r = getattr(self,'_rowHeights','[unknown]')
@@ -507,9 +554,15 @@
                 if ew is None: return None
                 w = max(w,ew)
             return w
-        elif isinstance(v,Flowable) and v._fixedWidth:
-            if hasattr(v, 'width') and isinstance(v.width,(int,float)): return 
v.width
-            if hasattr(v, 'drawWidth') and 
isinstance(v.drawWidth,(int,float)): return v.drawWidth
+        elif isinstance(v,Flowable):
+            if v._fixedWidth:
+                if hasattr(v, 'width') and isinstance(v.width,(int,float)): 
return v.width
+                if hasattr(v, 'drawWidth') and 
isinstance(v.drawWidth,(int,float)): return v.drawWidth
+            if hasattr(v,'__styledWrap__'): #very experimental
+                try:
+                    return getattr(v,'__styledWrap__')(s)[0]
+                except:
+                    pass
         # Even if something is fixedWidth, the attribute to check is not
         # necessarily consistent (cf. Image.drawWidth).  Therefore, we'll
         # be extra-careful and fall through to this code if necessary.
@@ -715,7 +768,7 @@
         and assign some best-guess values."""
 
         W = list(self._argW) # _calc_pc(self._argW,availWidth)
-        verbose = 0
+        #verbose = 1
         totalDefined = 0.0
         percentDefined = 0
         percentTotal = 0
@@ -733,8 +786,7 @@
             else:
                 assert isinstance(w,(int,float))
                 totalDefined = totalDefined + w
-        if verbose: print('prelim width calculation.  %d columns, %d undefined 
width, %0.2f units remain' % (
-            self._ncols, numberUndefined, availWidth - totalDefined))
+        #if verbose: print('prelim width calculation.  %d columns, %d 
undefined width, %0.2f units remain' % (self._ncols, numberUndefined, 
availWidth - totalDefined))
 
         #check columnwise in each None column to see if they are sizable.
         given = []
@@ -753,6 +805,7 @@
                     style = self._cellStyles[rowNo][colNo]
                     new = elementWidth(value,style) or 0
                     new += style.leftPadding+style.rightPadding
+                    #if verbose: print('[%d,%d] new=%r-->%r' % 
(rowNo,colNo,new - style.leftPadding+style.rightPadding, new))
                     final = max(final, new)
                     siz = siz and self._canGetWidth(value) # irrelevant now?
                 if siz:
@@ -765,21 +818,22 @@
                 given.append(colNo)
         if len(given) == self._ncols:
             return
-        if verbose: print('predefined width:   ',given)
-        if verbose: print('uncomputable width: ',unsizeable)
-        if verbose: print('computable width:   ',sizeable)
+        #if verbose: print('predefined width:   ',given)
+        #if verbose: print('uncomputable width: ',unsizeable)
+        #if verbose: print('computable width:   ',sizeable)
+        #if verbose: print('minimums=%r' % 
(list(sorted(list(minimums.items()))),))
 
         # how much width is left:
         remaining = availWidth - (totalMinimum + totalDefined)
         if remaining > 0:
             # we have some room left; fill it.
-            definedPercentage = (totalDefined/availWidth)*100
+            definedPercentage = (totalDefined/float(availWidth))*100
             percentTotal += definedPercentage
             if numberUndefined and percentTotal < 100:
                 undefined = numberGreedyUndefined or numberUndefined
-                defaultWeight = (100-percentTotal)/undefined
+                defaultWeight = (100-percentTotal)/float(undefined)
                 percentTotal = 100
-                defaultDesired = (defaultWeight/percentTotal)*availWidth
+                defaultDesired = (defaultWeight/float(percentTotal))*availWidth
             else:
                 defaultWeight = defaultDesired = 1
             # we now calculate how wide each column wanted to be, and then
@@ -826,7 +880,7 @@
                 # column is (104/264), which, multiplied  by the desired
                 # width of 264, is 104: the amount assigned to the remaining
                 # column.
-                proportion = effectiveRemaining/totalDesired
+                proportion = effectiveRemaining/float(totalDesired)
                 # we sort the desired widths by difference between desired and
                 # and minimum values, a value called "disappointment" in the
                 # code.  This means that the columns with a bigger
@@ -841,7 +895,7 @@
                         totalDesired -= desired
                         effectiveRemaining -= minimum
                         if totalDesired:
-                            proportion = effectiveRemaining/totalDesired
+                            proportion = effectiveRemaining/float(totalDesired)
                     else:
                         finalSet.append((minimum, desired, colNo))
                 for minimum, desired, colNo in finalSet:
@@ -851,7 +905,7 @@
         else:
             for colNo, minimum in minimums.items():
                 W[colNo] = minimum
-        if verbose: print('new widths are:', W)
+        #if verbose: print('new widths are:', W)
         self._argW = self._colWidths = W
         return W
 
@@ -1091,6 +1145,8 @@
             assert len(cmd) == 10
 
             self._linecmds.append(tuple(cmd))
+        elif cmd[0]=="ROUNDEDCORNERS":
+            self._setCornerRadii(cmd[1])
         else:
             (op, (sc, sr), (ec, er)), values = cmd[:3] , cmd[3:]
             if sr in ('splitfirst','splitlast'):
@@ -1104,25 +1160,48 @@
 
     def _drawLines(self):
         ccap, cdash, cjoin = None, None, None
-        self.canv.saveState()
-        for op, (sc,sr), (ec,er), weight, color, cap, dash, join, count, space 
in self._linecmds:
-            if isinstance(sr,strTypes) and sr.startswith('split'): continue
-            if cap!=None and ccap!=cap:
-                self.canv.setLineCap(cap)
-                ccap = cap
-            if dash is None or dash == []:
-                if cdash is not None:
-                    self.canv.setDash()
-                    cdash = None
-            elif dash != cdash:
-                self.canv.setDash(dash)
-                cdash = dash
-            if join is not None and cjoin!=join:
-                self.canv.setLineJoin(join)
-                cjoin = join
-            sc, ec, sr, er = self.normCellRange(sc,ec,sr,er)
-            getattr(self,_LineOpMap.get(op, '_drawUnknown' ))( (sc, sr), (ec, 
er), weight, color, count, space)
-        self.canv.restoreState()
+        canv = self.canv
+        canv.saveState()
+
+        rrd = self._roundingRectDef
+        if rrd: #we are collection some lines
+            SL = rrd.SL
+            SL[:] = []  #empty saved lines list
+            ocanvline = canv.line
+            aSL = SL.append
+            def rcCanvLine(xs, ys, xe, ye):
+                if  (
+                    (xs==xe and (xs>=rrd.x1 or xs<=rrd.x0)) #vertical line 
that needs to be saved
+                    or
+                    (ys==ye and (ys>=rrd.y1 or ys<=rrd.y0)) #horizontal line 
that needs to be saved
+                    ):
+                    
aSL(RoundingRectLine(xs,ys,xe,ye,weight,color,cap,dash,join))
+                else:
+                    ocanvline(xs,ys,xe,ye)
+            canv.line = rcCanvLine
+
+        try:
+            for op, (sc,sr), (ec,er), weight, color, cap, dash, join, count, 
space in self._linecmds:
+                if isinstance(sr,strTypes) and sr.startswith('split'): continue
+                if cap!=None and ccap!=cap:
+                    canv.setLineCap(cap)
+                    ccap = cap
+                if dash is None or dash == []:
+                    if cdash is not None:
+                        canv.setDash()
+                        cdash = None
+                elif dash != cdash:
+                    canv.setDash(dash)
+                    cdash = dash
+                if join is not None and cjoin!=join:
+                    canv.setLineJoin(join)
+                    cjoin = join
+                sc, ec, sr, er = self.normCellRange(sc,ec,sr,er)
+                getattr(self,_LineOpMap.get(op, '_drawUnknown' ))( (sc, sr), 
(ec, er), weight, color, count, space)
+        finally:
+            if rrd: 
+                canv.line = ocanvline
+        canv.restoreState()
         self._curcolor = None
 
     def _drawUnknown(self,  start, end, weight, color, count, space):
@@ -1306,12 +1385,14 @@
             splitH = self._rowHeights
         else:
             splitH = self._argH
+        cornerRadii = getattr(self,'_cornerRadii',None)
         R0 = self.__class__( data[:n], colWidths=self._colWidths, 
rowHeights=splitH[:n],
                 repeatRows=repeatRows, repeatCols=repeatCols,
                 splitByRow=splitByRow, normalizedData=1, 
cellStyles=self._cellStyles[:n],
                 ident=ident,
                 spaceBefore=getattr(self,'spaceBefore',None),
-                longTableOptimize=lto)
+                longTableOptimize=lto,
+                cornerRadii=cornerRadii[:2] if cornerRadii else None)
 
         nrows = self._nrows
         ncols = self._ncols
@@ -1392,6 +1473,7 @@
                     ident=ident,
                     spaceAfter=getattr(self,'spaceAfter',None),
                     longTableOptimize=lto,
+                    cornerRadii = cornerRadii,
                     )
             R1._cr_1_1(n,nrows,repeatRows,A) #linecommands
             R1._cr_1_1(n,nrows,repeatRows,self._bkgrndcmds,_srflMode=True)
@@ -1405,6 +1487,7 @@
                     ident=ident,
                     spaceAfter=getattr(self,'spaceAfter',None),
                     longTableOptimize=lto,
+                    cornerRadii = ([0,0] + cornerRadii[2:]) if cornerRadii 
else None,
                     )
             R1._cr_1_0(n,A)
             R1._cr_1_0(n,self._bkgrndcmds,_srflMode=True)
@@ -1463,7 +1546,117 @@
         else:
             raise NotImplementedError
 
+    def _makeRoundedCornersClip(self, FUZZ=rl_config._FUZZ):
+        self._roundingRectDef = None
+        cornerRadii = getattr(self,'_cornerRadii',None)
+        if not cornerRadii or max(cornerRadii)<=FUZZ: return
+        nrows = self._nrows
+        ncols = self._ncols
+        ar = [min(self._rowHeights[i],self._colWidths[j],cornerRadii[k]) for 
+                k,(i,j) in enumerate((
+                    (0,0),
+                    (0,ncols-1),
+                    (nrows-1,0),
+                    (nrows-1, ncols-1),
+                    ))]
+        rp = self._rowpositions
+        cp = self._colpositions
+
+        x0 = cp[0]
+        y0 = rp[nrows]
+        x1 = cp[ncols]
+        y1 = rp[0]
+        w = x1 - x0
+        h = y1 - y0
+        self._roundingRectDef = RoundingRectDef(x0, y0, w, h, x1, y1, ar, [])
+        P = self.canv.beginPath()
+        P.roundRect(x0, y0, w, h, ar)
+        c = self.canv
+        c.addLiteral('%begin table rect clip')
+        c.clipPath(P,stroke=0)
+        c.addLiteral('%end table rect clip')
+
+    def _restoreRoundingObscuredLines(self):
+        x0, y0, w, h, x1, y1, ar, SL = self._roundingRectDef
+        if not SL: return
+        canv = self.canv
+        canv.saveState()
+        ccap = cdash = cjoin = self._curweight = self._curcolor = None
+        line = canv.line
+        cornerRadii = self._cornerRadii
+        for (xs,ys,xe,ye,weight,color,cap,dash,join) in SL:
+            if cap!=None and ccap!=cap:
+                canv.setLineCap(cap)
+                ccap = cap
+            if dash is None or dash == []:
+                if cdash is not None:
+                    canv.setDash()
+                    cdash = None
+            elif dash != cdash:
+                canv.setDash(dash)
+                cdash = dash
+            if join is not None and cjoin!=join:
+                canv.setLineJoin(join)
+                cjoin = join
+            self._prepLine(weight, color)
+            if ys==ye:
+                #horizontal line
+                if ys>y1 or ys<y0:
+                    line(xs,ys,xe,ye)   #simple line that's outside the clip
+                    continue
+                #which corners are involved
+                if ys==y0:
+                    ypos = 'bottom'
+                    r0 = ar[2]
+                    r1 = ar[3]
+                else: #ys==y1
+                    ypos = 'top'
+                    r0 = ar[0]
+                    r1 = ar[1]
+                if xs>=x0+r0 and xe<=x1-r1:
+                    line(xs,ys,xe,ye)   #simple line with no rounding
+                    continue
+                #we have some rounding so we must use a path
+                c0 = _quadrantDef('left',ypos,(xs,ys), r0, kind=2, 
direction='left-right') if xs<x0+r0 else None
+                c1 = _quadrantDef('right',ypos,(xe,ye), r1, kind=1, 
direction='left-right') if xe>x1-r1 else None
+            else:
+                #vertical line
+                if xs>x1 or xs<x0:
+                    line(xs,ys,xe,ye)   #simple line that's outside the clip
+                    continue
+                #which corners are involved
+                if xs==x0:
+                    xpos = 'left'
+                    r0 = ar[2]
+                    r1 = ar[0]
+                else: #xs==x1
+                    xpos = 'right'
+                    r0 = ar[3]
+                    r1 = ar[1]
+                if ys>=y0+r0 and ye<=y1-r1:
+                    line(xs,ys,xe,ye)   #simple line with no rounding
+                    continue
+                #we have some rounding so we must use a path
+                c0 = _quadrantDef(xpos,'bottom',(xs,ys), r0, kind=2, 
direction='bottom-top') if ys<y0+r0 else None
+                c1 = _quadrantDef(xpos,'top',(xe,ye), r1, kind=1, 
direction='bottom-top') if ye>y1-r1 else None
+            P = canv.beginPath()
+            if c0:
+                P.moveTo(*c0[0])
+                P.curveTo(c0[1][0],c0[1][1],c0[2][0],c0[2][1], 
c0[3][0],c0[3][1])
+            else:
+                P.moveTo(xs,ys)
+            if not c1:
+                P.lineTo(xe,ye)
+            else:
+                P.lineTo(*c1[0])
+                P.curveTo(c1[1][0],c1[1][1],c1[2][0],c1[2][1], 
c1[3][0],c1[3][1])
+            canv.drawPath(P, stroke=1, fill=0)
+        canv.restoreState()
+
     def draw(self):
+        c = self.canv
+        c.saveState()
+        self._makeRoundedCornersClip()
         self._curweight = self._curcolor = self._curcellstyle = None
         self._drawBkgrnd()
         if not self._spanCmds:
@@ -1483,6 +1676,9 @@
                         cellstyle = self._cellStyles[rowNo][colNo]
                         self._drawCell(cellval, cellstyle, (x, y), (width, 
height))
         self._drawLines()
+        c.restoreState()
+        if self._roundingRectDef:
+            self._restoreRoundingObscuredLines()
 
     def _drawBkgrnd(self):
         nrows = self._nrows
@@ -1649,6 +1845,12 @@
             #external hyperlink
             self.canv.linkRect("", cellstyle.destination, Rect=(colpos, 
rowpos, colpos + colwidth, rowpos + rowheight), relative=1)
 
+    def _setCornerRadii(self, cornerRadii):
+        if isListOfNumbersOrNone(cornerRadii):
+            self._cornerRadii = None if not cornerRadii else list(cornerRadii) 
+ (max(4-len(cornerRadii),0)*[0])
+        else:
+            raise ValueError('cornerRadii should be None or a list/tuple of 
numeric radii')
+
 _LineOpMap = {  'GRID':'_drawGrid',
                 'BOX':'_drawBox',
                 'OUTLINE':'_drawBox',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/src/reportlab.egg-info/PKG-INFO 
new/reportlab-3.5.59/src/reportlab.egg-info/PKG-INFO
--- old/reportlab-3.5.56/src/reportlab.egg-info/PKG-INFO        2020-12-01 
17:29:31.000000000 +0100
+++ new/reportlab-3.5.59/src/reportlab.egg-info/PKG-INFO        2021-01-04 
15:52:21.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: reportlab
-Version: 3.5.56
+Version: 3.5.59
 Summary: The Reportlab Toolkit
 Home-page: http://www.reportlab.com/
 Author: Andy Robinson, Robin Becker, the ReportLab team and the community
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/src/rl_addons/rl_accel/_rl_accel.c 
new/reportlab-3.5.59/src/rl_addons/rl_accel/_rl_accel.c
--- old/reportlab-3.5.56/src/rl_addons/rl_accel/_rl_accel.c     2020-09-24 
15:27:24.000000000 +0200
+++ new/reportlab-3.5.59/src/rl_addons/rl_accel/_rl_accel.c     2020-12-27 
12:44:36.000000000 +0100
@@ -30,7 +30,7 @@
 #ifndef min
 #      define min(a,b) ((a)<(b)?(a):(b))
 #endif
-#define VERSION "0.75"
+#define VERSION "0.80"
 #define MODULE "_rl_accel"
 
 struct module_state    {
@@ -435,11 +435,37 @@
 
 static PyObject *escapePDF(PyObject *module, PyObject* args)
 {
-       unsigned char   *text;
-       Py_ssize_t              textLen;
+       unsigned char   *inData;
+       Py_ssize_t              length;
+       PyObject                *retVal=NULL, *inObj, *_o1=NULL;
 
-       if (!PyArg_ParseTuple(args, "s#:escapePDF", &text, &textLen)) return 
NULL;
-       return _escapePDF(text,textLen);
+       if (!PyArg_ParseTuple(args, "O:escapePDF", &inObj)) return NULL;
+       if(PyUnicode_Check(inObj)){
+               _o1 = PyUnicode_AsLatin1String(inObj);
+               if(!_o1){
+                       PyErr_SetString(PyExc_ValueError,"argument not 
decodable as latin1");
+                       ERROR_EXIT();
+                       }
+               inData = PyBytes_AsString(_o1);
+               inObj = _o1;
+               if(!inData){
+                       PyErr_SetString(PyExc_ValueError,"argument not 
converted to internal char string");
+                       ERROR_EXIT();
+                       }
+               }
+       else if(!PyBytes_Check(inObj)){
+               PyErr_SetString(PyExc_ValueError,"argument should be " 
BYTESNAME " or latin1 decodable " STRNAME);
+               ERROR_EXIT();
+               }
+       inData = PyBytes_AsString(inObj);
+       length = PyBytes_GET_SIZE(inObj);
+       retVal = _escapePDF(inData,length);
+L_exit:
+       Py_XDECREF(_o1);
+       return retVal;
+L_ERR:
+       ADD_TB(module,"excapePDF");
+       goto L_exit;
 }
 
 static PyObject *sameFrag(PyObject *module, PyObject* args)
@@ -1240,7 +1266,7 @@
 PyDoc_STRVAR(__DOC__,
 "_rl_accel contains various accelerated utilities\n\
 \n\
-\tescapePDF makes a string safe for PDF\n\
+\tescapePDF makes a unicode or latin1 bytes safe for PDF\n\
 \n\
 \tasciiBase85Encode does what is says\n\
 \tasciiBase85Decode does what is says\n\
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_multibyte_jpn.py 
new/reportlab-3.5.59/tests/test_multibyte_jpn.py
--- old/reportlab-3.5.56/tests/test_multibyte_jpn.py    2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_multibyte_jpn.py    2020-12-27 
12:44:36.000000000 +0100
@@ -56,14 +56,16 @@
         # work in post Unicode world.
         pdfmetrics.registerFont(CIDFont('HeiseiMin-W3','90ms-RKSJ-V'))
         c.setFont('HeiseiMin-W3-90ms-RKSJ-V', 16)
-        c.drawString(450, 650, '\223\214\213\236 vertical Shift-JIS')
-        height = c.stringWidth('\223\214\213\236 vertical Shift-JIS', 
'HeiseiMin-W3-90ms-RKSJ-V', 16)
+        s = u'\223\214\213\236 vertical Shift-JIS'  #these are octal numbers
+        c.drawString(450, 650, s)
+        height = c.stringWidth(s, 'HeiseiMin-W3-90ms-RKSJ-V', 16)
         c.rect(450-8,650,16,-height)
 
         pdfmetrics.registerFont(CIDFont('HeiseiMin-W3','EUC-V'))
         c.setFont('HeiseiMin-W3-EUC-V', 16)
-        c.drawString(475, 650, '\xC5\xEC\xB5\xFE vertical EUC')
-        height = c.stringWidth('\xC5\xEC\xB5\xFE vertical EUC', 
'HeiseiMin-W3-EUC-V', 16)
+        s = u'\xC5\xEC\xB5\xFE vertical EUC'
+        c.drawString(475, 650, s)
+        height = c.stringWidth(s, 'HeiseiMin-W3-EUC-V', 16)
         c.rect(475-8,650,16,-height)
 
 
@@ -76,8 +78,9 @@
                                 wordWrap="CJK"
                                 )
         
-        gatwickText = 
'\xe3\x82\xac\xe3\x83\x88\xe3\x82\xa6\xe3\x82\xa3\xe3\x83\x83\xe3\x82\xaf\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xa8\xe9\x80\xa3\xe7\xb5\xa1\xe9\x80\x9a\xe8\xb7\xaf\xe3\x81\xa7\xe7\x9b\xb4\xe7\xb5\x90\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3\x82\x8b\xe5\x94\xaf\xe4\xb8\x80\xe3\x81\xae\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xa7\xe3\x81\x82\xe3\x82\x8b\xe5\xbd\x93\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xaf\xe3\x80\x81\xe8\xa1\x97\xe3\x81\xae\xe4\xb8\xad\xe5\xbf\x83\xe9\x83\xa8\xe3\x81\x8b\xe3\x82\x8930\xe5\x88\x86\xe3\x81\xae\xe5\xa0\xb4\xe6\x89\x80\xe3\x81\xab\xe3\x81\x94\xe3\x81\x96\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe5\x85\xa8\xe5\xae\xa2\xe5\xae\xa4\xe3\x81\xab\xe9\xab\x98\xe9\x80\x9f\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x8d\xe3\x83\x83\xe3\x83\x88\xe7\x92\xb0\xe5\xa2\x83\xe3\x82\x92\xe5\xae\x8c\xe5\x82\x99\xe3\x81\x97\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x83\x95\xe3\x82\xa1
 
\xe3\x83\x9f\xe3\x83\xaa\xe3\x83\xbc\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xaf5\xe5\x90\x8d\xe6\xa7\x98\xe3\x81\xbe\xe3\x81\xa7\xe3\x81\x8a\xe6\xb3\x8a\xe3\x82\x8a\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x81\xbe\xe3\x81\x9f\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xae\xe3\x81\x8a\xe5\xae\xa2\xe6\xa7\x98\xe3\x81\xaf\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xa9\xe3\x82\xa6\xe3\x83\xb3\xe3\x82\xb8\xe3\x82\x92\xe3\x81\x94\xe5\x88\xa9\xe7\x94\xa8\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe4\xba\x8b\xe5\x89\x8d\xe3\x81\xab\xe3\x81\x94\xe4\xba\x88\xe7\xb4\x84\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x82\x8b\xe3\x82\xbf\xe3\x82\xa4\xe3\x83\xa0\xe3\x83\x88\xe3\x82\xa5\xe3\x83\x95\xe3\x83\xa9\xe3\x82\xa4\xe3\x83\xbb\xe3\x83\x91
 
\xe3\x83\x83\xe3\x82\xb1\xe3\x83\xbc\xe3\x82\xb8\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x81\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xae\xe9\xa7\x90\xe8\xbb\x8a\xe6\x96\x99\xe9\x87\x91\xe3\x81\x8c\xe5\x90\xab\xe3\x81\xbe\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82'
-        gatwickText2= 
'\xe3\x82\xac\xe3\x83\x88\xe3\x82\xa6\xe3\x82\xa3\xe3\x83\x83\xe3\x82\xaf<font 
color=red>\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xa8\xe9\x80\xa3\xe7\xb5\xa1\xe9\x80\x9a\xe8\xb7\xaf\xe3\x81\xa7\xe7\x9b\xb4\xe7\xb5\x90</font>\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3\x82\x8b\xe5\x94\xaf\xe4\xb8\x80\xe3\x81\xae\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xa7\xe3\x81\x82\xe3\x82\x8b\xe5\xbd\x93\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xaf\xe3\x80\x81\xe8\xa1\x97\xe3\x81\xae\xe4\xb8\xad\xe5\xbf\x83\xe9\x83\xa8\xe3\x81\x8b\xe3\x82\x8930\xe5\x88\x86\xe3\x81\xae\xe5\xa0\xb4\xe6\x89\x80\xe3\x81\xab\xe3\x81\x94\xe3\x81\x96\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe5\x85\xa8\xe5\xae\xa2\xe5\xae\xa4\xe3\x81\xab\xe9\xab\x98\xe9\x80\x9f\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x8d\xe3\x83\x83\xe3\x83\x88<link
 fg="blue" 
href="http://www.reportlab.com";>\xe7\x92\xb0\xe5\xa2\x83\xe3\x82\x92\xe5\xae\x8c\xe5\x82\x99</link>\xe3\x81\x97\xe3\x81\xa6<u>\xe
 
3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99</u>\xe3\x80\x82\xe3\x83\x95\xe3\x82\xa1\xe3\x83\x9f\xe3\x83\xaa\xe3\x83\xbc\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xaf5\xe5\x90\x8d\xe6\xa7\x98\xe3\x81\xbe\xe3\x81\xa7\xe3\x81\x8a\xe6\xb3\x8a\xe3\x82\x8a\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x81\xbe\xe3\x81\x9f\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xae\xe3\x81\x8a\xe5\xae\xa2\xe6\xa7\x98\xe3\x81\xaf\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xa9\xe3\x82\xa6\xe3\x83\xb3\xe3\x82\xb8\xe3\x82\x92\xe3\x81\x94\xe5\x88\xa9\xe7\x94\xa8\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe4\xba\x8b\xe5\x89\x8d\xe3\x81\xab\xe3\x81\x94\xe4\xba\x88\xe7\xb4\x84\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x82\x8b\xe3\x82\xbf\xe3\x82\xa4\xe3\x83\xa
 
0\xe3\x83\x88\xe3\x82\xa5\xe3\x83\x95\xe3\x83\xa9\xe3\x82\xa4\xe3\x83\xbb\xe3\x83\x91\xe3\x83\x83\xe3\x82\xb1\xe3\x83\xbc\xe3\x82\xb8\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x81\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xae\xe9\xa7\x90\xe8\xbb\x8a\xe6\x96\x99\xe9\x87\x91\xe3\x81\x8c\xe5\x90\xab\xe3\x81\xbe\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82'
+        #this is utf8
+        gatwickText = 
b'\xe3\x82\xac\xe3\x83\x88\xe3\x82\xa6\xe3\x82\xa3\xe3\x83\x83\xe3\x82\xaf\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xa8\xe9\x80\xa3\xe7\xb5\xa1\xe9\x80\x9a\xe8\xb7\xaf\xe3\x81\xa7\xe7\x9b\xb4\xe7\xb5\x90\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3\x82\x8b\xe5\x94\xaf\xe4\xb8\x80\xe3\x81\xae\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xa7\xe3\x81\x82\xe3\x82\x8b\xe5\xbd\x93\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xaf\xe3\x80\x81\xe8\xa1\x97\xe3\x81\xae\xe4\xb8\xad\xe5\xbf\x83\xe9\x83\xa8\xe3\x81\x8b\xe3\x82\x8930\xe5\x88\x86\xe3\x81\xae\xe5\xa0\xb4\xe6\x89\x80\xe3\x81\xab\xe3\x81\x94\xe3\x81\x96\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe5\x85\xa8\xe5\xae\xa2\xe5\xae\xa4\xe3\x81\xab\xe9\xab\x98\xe9\x80\x9f\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x8d\xe3\x83\x83\xe3\x83\x88\xe7\x92\xb0\xe5\xa2\x83\xe3\x82\x92\xe5\xae\x8c\xe5\x82\x99\xe3\x81\x97\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x83\x95\xe3\x82\xa
 
1\xe3\x83\x9f\xe3\x83\xaa\xe3\x83\xbc\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xaf5\xe5\x90\x8d\xe6\xa7\x98\xe3\x81\xbe\xe3\x81\xa7\xe3\x81\x8a\xe6\xb3\x8a\xe3\x82\x8a\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x81\xbe\xe3\x81\x9f\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xae\xe3\x81\x8a\xe5\xae\xa2\xe6\xa7\x98\xe3\x81\xaf\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xa9\xe3\x82\xa6\xe3\x83\xb3\xe3\x82\xb8\xe3\x82\x92\xe3\x81\x94\xe5\x88\xa9\xe7\x94\xa8\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe4\xba\x8b\xe5\x89\x8d\xe3\x81\xab\xe3\x81\x94\xe4\xba\x88\xe7\xb4\x84\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x82\x8b\xe3\x82\xbf\xe3\x82\xa4\xe3\x83\xa0\xe3\x83\x88\xe3\x82\xa5\xe3\x83\x95\xe3\x83\xa9\xe3\x82\xa4\xe3\x83\xbb\xe3\x83\x9
 
1\xe3\x83\x83\xe3\x82\xb1\xe3\x83\xbc\xe3\x82\xb8\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x81\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xae\xe9\xa7\x90\xe8\xbb\x8a\xe6\x96\x99\xe9\x87\x91\xe3\x81\x8c\xe5\x90\xab\xe3\x81\xbe\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82'
+        gatwickText2= 
b'\xe3\x82\xac\xe3\x83\x88\xe3\x82\xa6\xe3\x82\xa3\xe3\x83\x83\xe3\x82\xaf<font 
color=red>\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xa8\xe9\x80\xa3\xe7\xb5\xa1\xe9\x80\x9a\xe8\xb7\xaf\xe3\x81\xa7\xe7\x9b\xb4\xe7\xb5\x90</font>\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3\x82\x8b\xe5\x94\xaf\xe4\xb8\x80\xe3\x81\xae\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xa7\xe3\x81\x82\xe3\x82\x8b\xe5\xbd\x93\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xaf\xe3\x80\x81\xe8\xa1\x97\xe3\x81\xae\xe4\xb8\xad\xe5\xbf\x83\xe9\x83\xa8\xe3\x81\x8b\xe3\x82\x8930\xe5\x88\x86\xe3\x81\xae\xe5\xa0\xb4\xe6\x89\x80\xe3\x81\xab\xe3\x81\x94\xe3\x81\x96\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe5\x85\xa8\xe5\xae\xa2\xe5\xae\xa4\xe3\x81\xab\xe9\xab\x98\xe9\x80\x9f\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x8d\xe3\x83\x83\xe3\x83\x88<link
 fg="blue" 
href="http://www.reportlab.com";>\xe7\x92\xb0\xe5\xa2\x83\xe3\x82\x92\xe5\xae\x8c\xe5\x82\x99</link>\xe3\x81\x97\xe3\x81\xa6<u>\x
 
e3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99</u>\xe3\x80\x82\xe3\x83\x95\xe3\x82\xa1\xe3\x83\x9f\xe3\x83\xaa\xe3\x83\xbc\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xaf5\xe5\x90\x8d\xe6\xa7\x98\xe3\x81\xbe\xe3\x81\xa7\xe3\x81\x8a\xe6\xb3\x8a\xe3\x82\x8a\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x81\xbe\xe3\x81\x9f\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xae\xe3\x81\x8a\xe5\xae\xa2\xe6\xa7\x98\xe3\x81\xaf\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xa9\xe3\x82\xa6\xe3\x83\xb3\xe3\x82\xb8\xe3\x82\x92\xe3\x81\x94\xe5\x88\xa9\xe7\x94\xa8\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe4\xba\x8b\xe5\x89\x8d\xe3\x81\xab\xe3\x81\x94\xe4\xba\x88\xe7\xb4\x84\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x82\x8b\xe3\x82\xbf\xe3\x82\xa4\xe3\x83\x
 
a0\xe3\x83\x88\xe3\x82\xa5\xe3\x83\x95\xe3\x83\xa9\xe3\x82\xa4\xe3\x83\xbb\xe3\x83\x91\xe3\x83\x83\xe3\x82\xb1\xe3\x83\xbc\xe3\x82\xb8\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x81\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xae\xe9\xa7\x90\xe8\xbb\x8a\xe6\x96\x99\xe9\x87\x91\xe3\x81\x8c\xe5\x90\xab\xe3\x81\xbe\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82'
 
         c.setFont('HeiseiMin-W3', 12)
         jPara = Paragraph(gatwickText, jStyle)
@@ -253,16 +256,23 @@
 ##        c.showPage()
 
         from reportlab.lib import textsplit
-        
+        def sascii(x):
+            s = ascii(x)
+            if s.startswith('u') or s.startswith('b'): s = s[1:]
+            if s.startswith("'") or s.startswith('"'): s = s[1:]
+            if s.startswith('\\u') or s.startswith('\\x'): s = s[1:]
+            if s.endswith("'") or s.endswith('"'): s = s[:-1]
+            return s
+
         c.setFont('HeiseiMin-W3', 14)
         y = 700
-        c.drawString(70, y, 'cannot end line')
+        c.drawString(70, y, 'cannot start line')
         y -= 20
         for group in textsplit.CANNOT_START_LINE:
             c.drawString(70, y, group)
             y -= 20
             c.setFont('Helvetica',10)
-            c.drawString(70, y, ' '.join([ascii(x)[4:-1] for x in group]))
+            c.drawString(70, y, ' '.join([sascii(x) for x in group]))
             c.setFont('HeiseiMin-W3', 14)
             y -= 20
 
@@ -275,7 +285,7 @@
             c.drawString(70, y, group)
             y -= 20
             c.setFont('Helvetica',10)
-            c.drawString(70, y, ' '.join([ascii(x)[2:] for x in group]))
+            c.drawString(70, y, ' '.join([sascii(x) for x in group]))
             c.setFont('HeiseiMin-W3', 14)
             y -= 20
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_paragraphs.py 
new/reportlab-3.5.59/tests/test_paragraphs.py
--- old/reportlab-3.5.56/tests/test_paragraphs.py       2020-07-20 
09:39:52.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_paragraphs.py       2020-12-27 
12:44:36.000000000 +0100
@@ -5,13 +5,14 @@
 from reportlab import xrange
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import unittest, os
+import unittest, os, random
 from reportlab.platypus import Paragraph, SimpleDocTemplate, XBox, Indenter, 
XPreformatted, PageBreak, Spacer
 from reportlab.lib.styles import ParagraphStyle
 from reportlab.lib.units import inch
 from reportlab.lib.abag import ABag
 from reportlab.lib.colors import red, black, navy, white, green
 from reportlab.lib.randomtext import randomText
+from reportlab.rl_config import invariant as rl_invariant
 from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
 from reportlab.rl_config import defaultPageSize, rtlSupport
 from reportlab.pdfbase import ttfonts
@@ -83,7 +84,7 @@
             2. ...
             3. ...
         """
-
+        if rl_invariant: random.seed(1854640162)
         story = []
         SA = story.append
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_pdfbase_ttfonts.py 
new/reportlab-3.5.59/tests/test_pdfbase_ttfonts.py
--- old/reportlab-3.5.56/tests/test_pdfbase_ttfonts.py  2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_pdfbase_ttfonts.py  2020-12-27 
12:44:36.000000000 +0100
@@ -47,7 +47,7 @@
     font = _fonts[fontName]
     doc = c._doc
     kfunc = font.face.charToGlyph.keys if isPy3 else 
font.face.charToGlyph.iterkeys
-    for s in kfunc():
+    for s in sorted(list(kfunc())):
         if s<0x10000:
             font.splitString(uniChr(s),doc)
     state = font.state[doc]
@@ -55,7 +55,7 @@
     #print('len(assignments)=%d'%  len(state.assignments))
     nzero = 0
     ifunc = state.assignments.items if isPy3 else state.assignments.iteritems
-    for code, n in ifunc():
+    for code, n in sorted(list(ifunc())):
         if code==0: nzero += 1
         cn[n] = uniChr(code)
     if nzero>1: print('%s there were %d zero codes' % (fontName,nzero))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_pdfgen_general.py 
new/reportlab-3.5.59/tests/test_pdfgen_general.py
--- old/reportlab-3.5.56/tests/test_pdfgen_general.py   2020-09-18 
15:27:00.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_pdfgen_general.py   2021-01-01 
19:09:10.000000000 +0100
@@ -463,6 +463,12 @@
     t.textLine('canvas.rect(x, y, width, height) - x,y is lower left')
 
     c.roundRect(inch,6.25*inch,2*inch,0.6*inch,0.1*inch)
+    c.saveState()
+    c.setStrokeColor(red)
+    c.roundRect(inch*1.1,6.35*inch,1.8*inch,0.4*inch,[0.1*inch,0,0.09*inch,0])
+    c.setStrokeColor(green)
+    c.roundRect(inch*1.15,6.40*inch,1.7*inch,0.3*inch,[0,0.1*inch,0,0.09*inch])
+    c.restoreState()
     t.setTextOrigin(4*inch, 6.55*inch)
     t.textLine('canvas.roundRect(x,y,width,height,radius)')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_breaking.py 
new/reportlab-3.5.59/tests/test_platypus_breaking.py
--- old/reportlab-3.5.56/tests/test_platypus_breaking.py        2020-09-02 
14:34:06.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_platypus_breaking.py        2020-12-27 
12:44:36.000000000 +0100
@@ -5,7 +5,8 @@
 __version__='3.3.0'
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import sys, os, time, re
+import sys, os, time, re, random
+from reportlab.rl_config import invariant as rl_invariant
 from operator import truth
 import unittest
 from reportlab.platypus.flowables import Flowable, KeepTogether, 
KeepTogetherSplitAtTop
@@ -63,6 +64,7 @@
 def _test0(self):
     "This makes one long multi-page paragraph in test_platypus_breaking."
 
+    if rl_invariant: random.seed(1532760416)
     def RT(k,theme='PYTHON',sentences=1,cache={}):
         if k not in cache:
             cache[k] = randomText(theme=theme,sentences=sentences)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_cjk_wrap.py 
new/reportlab-3.5.59/tests/test_platypus_cjk_wrap.py
--- old/reportlab-3.5.56/tests/test_platypus_cjk_wrap.py        2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_platypus_cjk_wrap.py        2020-12-27 
12:44:36.000000000 +0100
@@ -20,10 +20,10 @@
 
 
 #says "Japanese is difficult, isn't it?"
-shortText = 
'\u65e5\u672c\u8a9e\u306f\u96e3\u3057\u3044\u3067\u3059\u306d\uff01'
+shortText = 
u'\u65e5\u672c\u8a9e\u306f\u96e3\u3057\u3044\u3067\u3059\u306d\uff01'
 
 
-gatwickText = 
'\xe3\x82\xac\xe3\x83\x88\xe3\x82\xa6\xe3\x82\xa3\xe3\x83\x83\xe3\x82\xaf\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xa8\xe9\x80\xa3\xe7\xb5\xa1\xe9\x80\x9a\xe8\xb7\xaf\xe3\x81\xa7\xe7\x9b\xb4\xe7\xb5\x90\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3\x82\x8b\xe5\x94\xaf\xe4\xb8\x80\xe3\x81\xae\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xa7\xe3\x81\x82\xe3\x82\x8b\xe5\xbd\x93\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xaf\xe3\x80\x81VERYLONGENGLISHGOESHERE\xe8\xa1\x97\xe3\x81\xae\xe4\xb8\xad\xe5\xbf\x83\xe9\x83\xa8\xe3\x81\x8b\xe3\x82\x8930\xe5\x88\x86\xe3\x81\xae\xe5\xa0\xb4\xe6\x89\x80\xe3\x81\xab\xe3\x81\x94\xe3\x81\x96\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe5\x85\xa8\xe5\xae\xa2\xe5\xae\xa4\xe3\x81\xab\xe9\xab\x98\xe9\x80\x9f\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x8d\xe3\x83\x83\xe3\x83\x88\xe7\x92\xb0\xe5\xa2\x83\xe3\x82\x92\xe5\xae\x8c\xe5\x82\x99\xe3\x81\x97\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x83\
 
x95\xe3\x82\xa1\xe3\x83\x9f\xe3\x83\xaa\xe3\x83\xbc\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xaf5\xe5\x90\x8d\xe6\xa7\x98\xe3\x81\xbe\xe3\x81\xa7\xe3\x81\x8a\xe6\xb3\x8a\xe3\x82\x8a\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x81\xbe\xe3\x81\x9f\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xae\xe3\x81\x8a\xe5\xae\xa2\xe6\xa7\x98\xe3\x81\xaf\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xa9\xe3\x82\xa6\xe3\x83\xb3\xe3\x82\xb8\xe3\x82\x92\xe3\x81\x94\xe5\x88\xa9\xe7\x94\xa8\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe4\xba\x8b\xe5\x89\x8d\xe3\x81\xab\xe3\x81\x94\xe4\xba\x88\xe7\xb4\x84\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x82\x8b\xe3\x82\xbf\xe3\x82\xa4\xe3\x83\xa0\xe3\x83\x88\xe3\x82\xa5\xe3\x83\x95\xe3\x83\xa9\xe3\x82\xa4\xe3\x83\
 
xbb\xe3\x83\x91\xe3\x83\x83\xe3\x82\xb1\xe3\x83\xbc\xe3\x82\xb8\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x81\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xae\xe9\xa7\x90\xe8\xbb\x8a\xe6\x96\x99\xe9\x87\x91\xe3\x81\x8c\xe5\x90\xab\xe3\x81\xbe\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82'
+gatwickText = 
b'\xe3\x82\xac\xe3\x83\x88\xe3\x82\xa6\xe3\x82\xa3\xe3\x83\x83\xe3\x82\xaf\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xa8\xe9\x80\xa3\xe7\xb5\xa1\xe9\x80\x9a\xe8\xb7\xaf\xe3\x81\xa7\xe7\x9b\xb4\xe7\xb5\x90\xe3\x81\x95\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x84\xe3\x82\x8b\xe5\x94\xaf\xe4\xb8\x80\xe3\x81\xae\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xa7\xe3\x81\x82\xe3\x82\x8b\xe5\xbd\x93\xe3\x83\x9b\xe3\x83\x86\xe3\x83\xab\xe3\x81\xaf\xe3\x80\x81VERYLONGENGLISHGOESHERE\xe8\xa1\x97\xe3\x81\xae\xe4\xb8\xad\xe5\xbf\x83\xe9\x83\xa8\xe3\x81\x8b\xe3\x82\x8930\xe5\x88\x86\xe3\x81\xae\xe5\xa0\xb4\xe6\x89\x80\xe3\x81\xab\xe3\x81\x94\xe3\x81\x96\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe5\x85\xa8\xe5\xae\xa2\xe5\xae\xa4\xe3\x81\xab\xe9\xab\x98\xe9\x80\x9f\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x8d\xe3\x83\x83\xe3\x83\x88\xe7\x92\xb0\xe5\xa2\x83\xe3\x82\x92\xe5\xae\x8c\xe5\x82\x99\xe3\x81\x97\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x83
 
\x95\xe3\x82\xa1\xe3\x83\x9f\xe3\x83\xaa\xe3\x83\xbc\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xaf5\xe5\x90\x8d\xe6\xa7\x98\xe3\x81\xbe\xe3\x81\xa7\xe3\x81\x8a\xe6\xb3\x8a\xe3\x82\x8a\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe3\x81\xbe\xe3\x81\x9f\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xab\xe3\x83\xbc\xe3\x83\xa0\xe3\x81\xae\xe3\x81\x8a\xe5\xae\xa2\xe6\xa7\x98\xe3\x81\xaf\xe3\x80\x81\xe3\x82\xa8\xe3\x82\xb0\xe3\x82\xbc\xe3\x82\xaf\xe3\x83\x86\xe3\x82\xa3\xe3\x83\x96\xe3\x83\xa9\xe3\x82\xa6\xe3\x83\xb3\xe3\x82\xb8\xe3\x82\x92\xe3\x81\x94\xe5\x88\xa9\xe7\x94\xa8\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82\xe4\xba\x8b\xe5\x89\x8d\xe3\x81\xab\xe3\x81\x94\xe4\xba\x88\xe7\xb4\x84\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x91\xe3\x82\x8b\xe3\x82\xbf\xe3\x82\xa4\xe3\x83\xa0\xe3\x83\x88\xe3\x82\xa5\xe3\x83\x95\xe3\x83\xa9\xe3\x82\xa4\xe3\x83
 
\xbb\xe3\x83\x91\xe3\x83\x83\xe3\x82\xb1\xe3\x83\xbc\xe3\x82\xb8\xe3\x81\xab\xe3\x81\xaf\xe3\x80\x81\xe7\xa9\xba\xe6\xb8\xaf\xe3\x81\xae\xe9\xa7\x90\xe8\xbb\x8a\xe6\x96\x99\xe9\x87\x91\xe3\x81\x8c\xe5\x90\xab\xe3\x81\xbe\xe3\x82\x8c\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82'
 
 def myMainPageFrame(canvas, doc):
     "The page frame used for all PDF documents."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_indents.py 
new/reportlab-3.5.59/tests/test_platypus_indents.py
--- old/reportlab-3.5.56/tests/test_platypus_indents.py 2020-01-22 
15:40:54.000000000 +0100
+++ new/reportlab-3.5.59/tests/test_platypus_indents.py 2020-12-27 
12:44:36.000000000 +0100
@@ -7,6 +7,7 @@
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
 import sys, os, random
+from reportlab.rl_config import invariant as rl_invariant
 from operator import truth
 import unittest
 from reportlab.pdfbase.pdfmetrics import stringWidth
@@ -65,6 +66,7 @@
 
     def test0(self):
         "IndentTestCase test0"
+        if rl_invariant: random.seed(1479316371)
 
         # Build story.
         story = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_index.py 
new/reportlab-3.5.59/tests/test_platypus_index.py
--- old/reportlab-3.5.56/tests/test_platypus_index.py   2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_platypus_index.py   2020-12-27 
12:44:36.000000000 +0100
@@ -6,7 +6,8 @@
 from reportlab import xrange
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import sys, os
+import sys, os, random
+from reportlab.rl_config import invariant as rl_invariant
 from os.path import join, basename, splitext
 from math import sqrt
 import unittest
@@ -83,6 +84,7 @@
         Index terms are grouped by their first 2, and first 3 characters.
         The page numbers should be clickable and link to the indexed word.
         '''
+        if rl_invariant: random.seed(1753799561)
         # Build story.
         
         for headers in False, True:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_leftright.py 
new/reportlab-3.5.59/tests/test_platypus_leftright.py
--- old/reportlab-3.5.56/tests/test_platypus_leftright.py       2020-01-22 
15:40:54.000000000 +0100
+++ new/reportlab-3.5.59/tests/test_platypus_leftright.py       2020-12-27 
12:44:36.000000000 +0100
@@ -5,7 +5,8 @@
 __version__='3.3.0'
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import sys, os, time
+import sys, os, time, random
+from reportlab.rl_config import invariant as rl_invariant
 from operator import truth
 import unittest
 from reportlab.platypus.flowables import Flowable
@@ -88,6 +89,7 @@
     def testIt(self):
         "LeftRightTestCase.testit"
 
+        if rl_invariant: random.seed(464568862)
         # Build story.
         story = []
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_lists.py 
new/reportlab-3.5.59/tests/test_platypus_lists.py
--- old/reportlab-3.5.56/tests/test_platypus_lists.py   2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_platypus_lists.py   2020-12-27 
12:44:36.000000000 +0100
@@ -3,7 +3,8 @@
 from reportlab import xrange
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import os,unittest
+import os,unittest, random
+from reportlab.rl_config import invariant as rl_invariant
 from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, 
ListFlowable, ListItem, \
         Paragraph, PageBreak, DDIndenter, MultiCol
 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
@@ -60,6 +61,7 @@
     "Make documents with tables"
 
     def test1(self):
+        if rl_invariant: random.seed(888147853)
         styleSheet = getSampleStyleSheet()
         doc = 
SimpleDocTemplate(outputfile('test_platypus_lists1.pdf'),showBoundary=True)
         story=[]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_paragraphs.py 
new/reportlab-3.5.59/tests/test_platypus_paragraphs.py
--- old/reportlab-3.5.56/tests/test_platypus_paragraphs.py      2020-10-29 
17:06:02.000000000 +0100
+++ new/reportlab-3.5.59/tests/test_platypus_paragraphs.py      2020-12-27 
12:44:36.000000000 +0100
@@ -15,7 +15,7 @@
 from reportlab.lib.colors import Color
 from reportlab.lib.units import cm
 from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
-from reportlab.lib.utils import _className, asBytes, asUnicode
+from reportlab.lib.utils import _className, asBytes, asUnicode, asNative
 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
 from reportlab.platypus.xpreformatted import XPreformatted
 from reportlab.platypus.frames import Frame, ShowBoundaryValue
@@ -186,13 +186,74 @@
         style = ParagraphStyle(
             'normal', fontName='Helvetica', fontSize=12,
             embeddedHyphenation=1, splitLongWords=0, hyphenationLang='en-GB')
-        text = 
'Super\xc2\xadcali\xc2\xadfragi\xc2\xadlistic\xc2\xadexpi\xc2\xadali\xc2\xaddocious'
+        shy = asNative(u'\xad')
+        text = 
shy.join(('Super','cali','fragi','listic','expi','ali','docious'))
         f.addFromList([Paragraph(text, style)], c)
         text = u'<span color="red">Super</span><span 
color="pink">&#173;cali&#173;</span>fragi&#173;listic&#173;expi&#173;ali&#173;docious'
         f.addFromList([Paragraph(text, style)], c)
         c.showPage()
         c.save() 
 
+    def test_platypus_paragraphs_embedded2(self):
+        from hashlib import md5 as hashlib_md5
+
+        fontName = 'Helvetica'
+        fontSize = 10
+
+        texts = [asUnicode(text) for text
+                in  [
+                    b'UU\xc2\xadDIS\xc2\xadTU\xc2\xadSA\xc2\xadLA JA 
TAI\xc2\xadMIK\xc2\xadKO',
+                    b'NUO\xc2\xadRI 
KAS\xc2\xadVA\xc2\xadTUS\xc2\xadMET\xc2\xadSIK\xc2\xadK\xc3\x96',
+                    b'VART\xc2\xadTU\xc2\xadNUT 
KAS\xc2\xadVA\xc2\xadTUS\xc2\xadMET\xc2\xadSIK\xc2\xadK\xc3\x96',
+                    b'UU\xc2\xadDIS\xc2\xadTUS-KYP\xc2\xadS\xc3\x84 
MET\xc2\xadSIK\xc2\xadK\xc3\x96',
+                    b'SIE\xc2\xadMEN- JA 
SUO-JUS\xc2\xadPUU-MET\xc2\xadSIK\xc2\xadK\xc3\x96',
+                    
b'E\xc2\xadRI-I\xc2\xadK\xc3\x84\xc2\xadIS-RA\xc2\xadKEN\xc2\xadTEI\xc2\xadNEN 
MET\xc2\xadSIK\xc2\xadK\xc3\x96',
+                    ]
+                ]
+        maxWidth = stringWidth('VARTTUNUT KAS', fontName, fontSize)+0.5
+        span = lambda _t, _c: "<span color='%s'>%s</span>" % (_c, _t)
+
+        pagesize = (20+maxWidth, 800)
+        c = Canvas(outputfile('test_platypus_paragraphs_embedded2.pdf'), 
pagesize=pagesize)
+
+        expected = [
+                (163, b'\x7f\xd7_^\x07\x9c!u\x02\xb4\x13z\xb5y6C'),
+                (163, b'\xab\x82\xbf\xb3\xfc\xb5\xaau\x15\xb1<\x8eX\xbe35'),
+                (163, b'LL\xb1\xfd.\x8a\x8bk\xde\xcdK\x16P\xebWh'),
+                (163, b'\xa9fj\xdd\xb9\x11N\xcf\xbb\x12\xfb\xd9\xa5\xf0v<'),
+                (163, b'\x18r\x98\x17\xd8&\x8c\x01{\xf3|r\xca\xccQy'),
+                (163, b'\xb7\xf2\x0f/d\xe9<\xd1B?\xe5\x8c\xcbO\x06?'),
+                ]
+        observed = []
+        for eh in 0, 1, 2:
+            for slw in 0, 1:
+                f = Frame(10, 10, maxWidth, 780,
+                        showBoundary=ShowBoundaryValue(dashArray=(1,1)),
+                        leftPadding=0,
+                        rightPadding=0,
+                        topPadding=0,
+                        bottomPadding=0,
+                        )
+                style = ParagraphStyle(
+                    'normal', fontName=fontName, fontSize=fontSize,
+                    embeddedHyphenation=eh, splitLongWords=slw,
+                    hyphenationLang=None)
+                f.addFromList([Paragraph('slw=%d eh=%d' % (slw,eh), style)], c)
+                for text in texts:
+                    f.addFromList([Paragraph(text, style)], c)
+                    mfText = text.split(u'\xad')
+                    mfText[0] = span(mfText[0],'red')
+                    if len(mfText)>1:
+                        mfText[1] = span(mfText[1],'pink')
+                        if len(mfText)>2:
+                            mfText[-1] = span(mfText[-1],'blue')
+                    mfText = u'&#173;'.join(mfText)
+                    f.addFromList([Paragraph(mfText, style)], c)
+                observed.append((len(c._code), 
hashlib_md5(b"".join((asBytes(b,"latin1") for b in c._code))).digest()))
+                c.showPage()
+        c.save() 
+        self.assertEqual(observed, expected)
+
     def test_lele_img(self):
         from reportlab.pdfgen.canvas import Canvas
         from reportlab.platypus import Paragraph
@@ -621,9 +682,9 @@
         \xd7\x93\xd7\xa8\xd7\x9b\xd7\x94 
\xd7\xa9\xd7\x99\xd7\xaa\xd7\x95\xd7\xa4\xd7\x99\xd7\xaa
         \xd7\x90\xd7\xaa\xd7\x94 \xd7\x93\xd7\xaa.'''
         gif = os.path.join(testsFolder,'pythonpowered.gif')
-        heading = Paragraph('\xd7\x96\xd7\x95\xd7\x94\xd7\x99 
\xd7\x9b\xd7\x95\xd7\xaa\xd7\xa8\xd7\xaa',h3)
+        heading = Paragraph(b'\xd7\x96\xd7\x95\xd7\x94\xd7\x99 
\xd7\x9b\xd7\x95\xd7\xaa\xd7\xa8\xd7\xaa',h3)
         
story.append(ImageAndFlowables(Image(gif),[heading,Paragraph(text,bt)]))
-        heading = Paragraph('\xd7\x96\xd7\x95\xd7\x94\xd7\x99 
\xd7\x9b\xd7\x95\xd7\xaa\xd7\xa8\xd7\xaa',h3)
+        heading = Paragraph(b'\xd7\x96\xd7\x95\xd7\x94\xd7\x99 
\xd7\x9b\xd7\x95\xd7\xaa\xd7\xa8\xd7\xaa',h3)
         
story.append(ImageAndFlowables(Image(gif),[heading,Paragraph(text1,bt)]))
         doc = 
MyDocTemplate(outputfile('test_platypus_imageandflowables_rtl.pdf'),showBoundary=1)
         doc.multiBuild(story)
@@ -1311,7 +1372,7 @@
     bt = getSampleStyleSheet()['BodyText']
     bt.fontName = 'DejaVuSans'
     doc = SimpleDocTemplate(fn)
-    story = [Paragraph('<b>%s</b>' % title,bt)]
+    story = [Paragraph('<b>%s</b>' % asNative(title),bt)]
     story.extend([Paragraph(bu('&amp;%s; = <span color="red">&%s;</span>' % 
(k,k)), bt) for k, v in alphaSortedItems(greeks)])
     doc.build(story)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/reportlab-3.5.56/tests/test_platypus_pleaseturnover.py 
new/reportlab-3.5.59/tests/test_platypus_pleaseturnover.py
--- old/reportlab-3.5.56/tests/test_platypus_pleaseturnover.py  2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_platypus_pleaseturnover.py  2020-12-27 
12:44:36.000000000 +0100
@@ -5,8 +5,7 @@
 __version__='3.3.0'
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import sys
-import unittest
+import sys, unittest
 from reportlab.platypus.flowables import Flowable, PTOContainer, KeepInFrame
 from reportlab.platypus import FrameBG
 from reportlab.lib.units import cm
@@ -16,7 +15,6 @@
 from reportlab.platypus.paragraph import Paragraph
 from reportlab.platypus.tables import Table
 from reportlab.platypus.frames import Frame
-from reportlab.lib.randomtext import randomText
 from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate, 
FrameBreak
 
 def myMainPageFrame(canvas, doc):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_preformatted.py 
new/reportlab-3.5.59/tests/test_platypus_preformatted.py
--- old/reportlab-3.5.56/tests/test_platypus_preformatted.py    2020-01-22 
15:40:54.000000000 +0100
+++ new/reportlab-3.5.59/tests/test_platypus_preformatted.py    2020-12-27 
12:44:36.000000000 +0100
@@ -5,7 +5,7 @@
 __version__='3.3.0'
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import sys, os, random
+import sys, os
 from operator import truth
 import unittest
 from reportlab.pdfbase.pdfmetrics import stringWidth
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_programming.py 
new/reportlab-3.5.59/tests/test_platypus_programming.py
--- old/reportlab-3.5.56/tests/test_platypus_programming.py     2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_platypus_programming.py     2020-12-27 
12:44:36.000000000 +0100
@@ -7,8 +7,7 @@
 """
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import sys
-import unittest
+import sys, unittest
 class PlatypusProgrammingTestCase(unittest.TestCase):
     "test platypus programming"
 
@@ -60,6 +59,9 @@
         from reportlab.platypus import Paragraph
         from reportlab.lib import colors
         from reportlab.lib.randomtext import randomText, PYTHON
+        import random
+        from reportlab.rl_config import invariant as rl_invariant
+        if rl_invariant: random.seed(2103696747)
 
         # Build story.
         story = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_tables.py 
new/reportlab-3.5.59/tests/test_platypus_tables.py
--- old/reportlab-3.5.56/tests/test_platypus_tables.py  2020-12-01 
17:29:04.000000000 +0100
+++ new/reportlab-3.5.59/tests/test_platypus_tables.py  2021-01-04 
15:51:54.000000000 +0100
@@ -1066,6 +1066,72 @@
         self.assertEqual(len(T[1]._bkgrndcmds),3)
         doc.build(story)
 
+    def test5(self):
+        '''test rounded corners'''
+        story = []
+        story_add = story.append
+        ts_tables = [
+                 ('BACKGROUND',(0,0),(-1,0),colors.pink),
+                 ('BACKGROUND',(0,1),(-1,1),colors.lightblue),
+                 ('ROWBACKGROUNDS',(0,2),(-1,-1),(colors.lightgrey,None)),
+                 ('TEXTCOLOR',(0,0),(-1,0),colors.green),
+                 ('TEXTCOLOR',(0,1),(-1,1),colors.red),
+                 ('LINEABOVE', (0,0), (-1,0), 1, colors.purple),
+                 ('LINEBELOW', (0,0), (-1,0), 2, colors.purple),
+                 ('LINEABOVE', (0,1), (-1,1), 1, colors.orange),
+                 ('LINEBELOW', (0,1), (-1,1), 2, colors.orange),
+                 ('LINEBEFORE', (0,0), (0,-1), 1, colors.red),
+                 ('LINEAFTER', (-1,0), (-1,-1), 1, colors.blue),
+                 ('LINEBELOW', (0,-1), (-1,-1), 1, colors.green),
+                 ('FONT', (2,2), (5,8), 'Times-Bold'),
+                 ]
+        data = self.data34
+        from reportlab.platypus import Paragraph, Table, SimpleDocTemplate, 
PageBreak
+        from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
+        styleSheet = getSampleStyleSheet()
+        bodyText = styleSheet['BodyText']
+
+        story_add(Paragraph('The whole table',bodyText))
+        t = Table(data[:], style=ts_tables, repeatRows=2, 
cornerRadii=[5,6,4,3])
+        story_add(t)
+        t = Table(data[:], style=ts_tables, repeatRows=2, 
cornerRadii=[5,6,4,5])
+        T = t.split(4*72,90)
+        story_add(Paragraph('The split table part 0',bodyText))
+        story_add(T[0])
+        story_add(Paragraph('The split table part 1',bodyText))
+        story_add(T[1])
+        story_add(PageBreak())
+        ts2 = ts_tables+[('ROUNDEDCORNERS',[5,6,4,3])]
+        story_add(Paragraph('Rounded corners via style',bodyText))
+        t = Table(data[:], style=ts2, repeatRows=2)
+        story_add(t)
+        t = Table(data[:], style=ts2, repeatRows=2)
+        T = t.split(4*72,90)
+        story_add(Paragraph('The split table part 0',bodyText))
+        story_add(T[0])
+        story_add(Paragraph('The split table part 1',bodyText))
+        story_add(T[1])
+        story_add(PageBreak())
+        story_add(Paragraph('Rounded corners via style overridden by instance 
argument',bodyText))
+        t = Table(data[:], style=ts2, repeatRows=2, cornerRadii=(0,3,5,0))
+        story_add(t)
+        t = Table(data[:], style=ts2, repeatRows=2, cornerRadii=t._cornerRadii)
+        T = t.split(4*72,90)
+        story_add(Paragraph('The split table part 0',bodyText))
+        story_add(T[0])
+        story_add(Paragraph('The split table part 1',bodyText))
+        story_add(T[1])
+        story_add(Paragraph('Rounded corners double linebelow',bodyText))
+        ts3 = ts_tables[:]
+        ts3.remove(('LINEBELOW', (0,-1), (-1,-1), 1, colors.green))
+        ts3.append(('LINEBELOW', (0,-1), (-1,-1), 1, colors.green, 1, None, 
None, 3,1))
+        t = Table(data[:], style=ts3, repeatRows=2, 
cornerRadii=[0,0,6,7])#[4,5,6,7])
+        story_add(t)
+        doc = 
SimpleDocTemplate(outputfile('test_platypus_tables_rounded_corners.pdf'), 
showBoundary=0)
+        doc.build(story)
+        assert(T[0]._cornerRadii==[0,3,0,0])
+        assert(T[1]._cornerRadii==[0,3,5,0])
+
 def makeSuite():
     return makeSuiteForClasses(TablesTestCase)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_toc.py 
new/reportlab-3.5.59/tests/test_platypus_toc.py
--- old/reportlab-3.5.56/tests/test_platypus_toc.py     2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_platypus_toc.py     2020-12-27 
12:44:36.000000000 +0100
@@ -13,6 +13,7 @@
 from os.path import join, basename, splitext
 from math import sqrt
 import random
+from reportlab.rl_config import invariant as rl_invariant
 import unittest
 from reportlab.lib.units import inch, cm
 from reportlab.lib.pagesizes import A4
@@ -133,7 +134,7 @@
             3. Only entries of every second level has links
             ...
         """
-
+        if rl_invariant: random.seed(2077179149)
         maxLevels = 12
 
         # Create styles to be used for document headers
@@ -181,7 +182,7 @@
         with the right headings to make it go faster.  We used
         a simple 100-chapter document with one level.
         """
-
+        if rl_invariant: random.seed(1216902530)
         chapters = 30   #goes over one page
         
         headerStyle = makeHeaderStyle(0)
@@ -281,6 +282,7 @@
         self.assertTrue(hasattr(doc,'seq'))
 
     def test2(self):
+        if rl_invariant: random.seed(530125105)
         chapters = 20   #so we know we use only one page
         from reportlab.lib.colors import pink
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_wrapping.py 
new/reportlab-3.5.59/tests/test_platypus_wrapping.py
--- old/reportlab-3.5.56/tests/test_platypus_wrapping.py        2020-01-22 
15:40:54.000000000 +0100
+++ new/reportlab-3.5.59/tests/test_platypus_wrapping.py        2020-12-27 
12:44:36.000000000 +0100
@@ -5,7 +5,7 @@
 __version__='3.3.0'
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import sys, os, random
+import sys, os
 from operator import truth
 import unittest
 from reportlab.pdfbase.pdfmetrics import stringWidth
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_platypus_xref.py 
new/reportlab-3.5.59/tests/test_platypus_xref.py
--- old/reportlab-3.5.56/tests/test_platypus_xref.py    2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_platypus_xref.py    2020-12-27 
12:44:36.000000000 +0100
@@ -5,7 +5,8 @@
 __version__='3.3.0'
 from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
 setOutDir(__name__)
-import sys, os, time
+import sys, os, time, random
+from reportlab.rl_config import invariant as rl_invariant
 from operator import truth
 import unittest
 from reportlab.lib import colors
@@ -69,6 +70,7 @@
 def _test0(self):
     "This makes one long multi-page paragraph."
     from reportlab.platypus.flowables import DocAssign, DocExec, DocPara, 
DocIf, DocWhile
+    if rl_invariant: random.seed(1629812163)
 
     # Build story.
     story = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_rl_accel.py 
new/reportlab-3.5.59/tests/test_rl_accel.py
--- old/reportlab-3.5.56/tests/test_rl_accel.py 2019-10-01 17:38:11.000000000 
+0200
+++ new/reportlab-3.5.59/tests/test_rl_accel.py 2020-12-27 12:44:36.000000000 
+0100
@@ -81,8 +81,15 @@
 
     def testEscapePDF(self):
         for func, kind in getFuncs('escapePDF'):
-            assert func('(test)')=='\\(test\\)',"%s 
escapePDF('(test)')=='\\\\(test\\\\)' fails with value %s!" % (
-                    kind,ascii(func('(test)')))
+            for s, sx in (
+                    ('(test)', r'\(test\)'),
+                    (r'\(test)', r'\\\(test\)'),
+                    (b'\223\214\213\236',r'\223\214\213\236'),
+                    (u'\223\214\213\236',r'\223\214\213\236'),
+                    ):
+                r = func(s)
+                assert r==sx,"%s escapePDF('%s')=='%s' fails with value '%s'!" 
% (
+                    kind,s,sx,r)
 
     def testCalcChecksum(self):
         for func, kind in getFuncs('calcChecksum'):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-3.5.56/tests/test_source_chars.py 
new/reportlab-3.5.59/tests/test_source_chars.py
--- old/reportlab-3.5.56/tests/test_source_chars.py     2019-10-01 
17:38:11.000000000 +0200
+++ new/reportlab-3.5.59/tests/test_source_chars.py     2020-12-27 
12:44:36.000000000 +0100
@@ -23,6 +23,9 @@
 
         self.output = 
open(outputfile(os.path.splitext(os.path.basename(fn))[0]+'.txt'),'w')
 
+    def tearDown(self):
+        self.output.close()
+
     def checkFileForTabs(self, filename):
         txt = open_and_read(filename, 'r')
         chunks = txt.split('\t')

Reply via email to