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 2026-01-28 15:12:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-reportlab (Old)
 and      /work/SRC/openSUSE:Factory/.python-reportlab.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-reportlab"

Wed Jan 28 15:12:16 2026 rev:43 rq:1329544 version:4.4.9

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-reportlab/python-reportlab.changes        
2025-11-13 17:29:15.067901594 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-reportlab.new.1928/python-reportlab.changes  
    2026-01-28 15:15:04.881811068 +0100
@@ -1,0 +2,14 @@
+Tue Jan 27 17:20:35 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 4.4.9:
+  * remove unwanted debug
+  * fix callback security hole
+  * fix table layout error
+  * fix CHANGES versions wrongly marked as 4.3.x --> 4.4.x
+  * remove url from default PDF metadata
+  * remove random monkey patches in randomtext
+  * add and use testutils.invariantSeed in tests
+  * fix (maybe partially) Table row splitting of ListFlowable
+  * apply patch for in row splitting
+
+-------------------------------------------------------------------

Old:
----
  reportlab-4.4.4.tar.gz

New:
----
  reportlab-4.4.9.tar.gz

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

Other differences:
------------------
++++++ python-reportlab.spec ++++++
--- /var/tmp/diff_new_pack.5l941p/_old  2026-01-28 15:15:09.846017865 +0100
+++ /var/tmp/diff_new_pack.5l941p/_new  2026-01-28 15:15:09.846017865 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-reportlab
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-reportlab
-Version:        4.4.4
+Version:        4.4.9
 Release:        0
 Summary:        The Reportlab Toolkit
 License:        BSD-3-Clause


++++++ reportlab-4.4.4.tar.gz -> reportlab-4.4.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/CHANGES.md 
new/reportlab-4.4.9/CHANGES.md
--- old/reportlab-4.4.4/CHANGES.md      2025-09-19 12:35:51.000000000 +0200
+++ new/reportlab-4.4.9/CHANGES.md      2026-01-15 10:17:03.000000000 +0100
@@ -11,7 +11,31 @@
 The contributors lists are in no order and apologies to those accidentally not
 mentioned. If we missed you, please let us know!
 
-CHANGES  4.3.4   18/09/2025
+CHANGES  4.4.9   15/01/2026
+---------------------------
+    * remove unwanted debug
+
+CHANGES  4.4.8   15/01/2026
+---------------------------
+    * fix callback security hole reported by Pedro "gankd"  lt pedrovgcruz at 
icloud dot com gt
+
+CHANGES  4.4.7   21/12/2025
+---------------------------
+    * fix table layout error reported by Andy Hagar atboom33w at gmail dot com
+
+CHANGES  4.4.6   10/12/2025
+---------------------------
+    * fix CHANGES versions wrongly marked as 4.3.x --> 4.4.x
+    * remove url from default PDF metadata
+
+CHANGES  4.4.5   17/11/2025
+---------------------------
+    * remove random monkey patches in randomtext
+    * add and use testutils.invariantSeed in tests
+    * fix (maybe partially) Table row splitting of ListFlowable
+    * apply patch for in row splitting bug reported by Christian Zwicknagl via 
Yoshua Wakeham
+
+CHANGES  4.4.4   18/09/2025
 ---------------------------
     * raise an error for table cell flowables given negative width
     * fix the rotatedEnclosingRect algorithm so it allows variable angles
@@ -1101,6 +1125,8 @@
    * Michael Egorov <[email protected]>
    * Mike Folwell <[email protected]>
    * Robert Alsina
+   * Christian Zwicknagl
+   * Yoshua Wakeham
    * and more ...
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/PKG-INFO new/reportlab-4.4.9/PKG-INFO
--- old/reportlab-4.4.4/PKG-INFO        2025-09-19 12:38:42.718631000 +0200
+++ new/reportlab-4.4.9/PKG-INFO        2026-01-15 10:23:12.014963200 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: reportlab
-Version: 4.4.4
+Version: 4.4.9
 Summary: The Reportlab Toolkit
 Home-page: https://www.reportlab.com/
 Author: Andy Robinson, Robin Becker, the ReportLab team and the community
@@ -12,11 +12,11 @@
 Classifier: Topic :: Printing
 Classifier: Topic :: Text Processing :: Markup
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
 Requires-Python: >=3.9,<4
 License-File: LICENSE
 Requires-Dist: pillow>=9.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/setup.py new/reportlab-4.4.9/setup.py
--- old/reportlab-4.4.4/setup.py        2025-09-19 12:34:38.000000000 +0200
+++ new/reportlab-4.4.9/setup.py        2025-12-10 10:54:48.000000000 +0100
@@ -1,6 +1,6 @@
 #Copyright ReportLab Europe Ltd. 2000-2025
 #see LICENSE for license details
-__version__='4.4.0'
+__version__='4.4.5'
 import os, sys, glob, shutil, re, sysconfig, traceback, io, subprocess
 from urllib.parse import quote as urlquote
 platform = sys.platform
@@ -321,11 +321,11 @@
             'Topic :: Printing',
             'Topic :: Text Processing :: Markup',
             'Programming Language :: Python :: 3',
-            'Programming Language :: Python :: 3.9',
             'Programming Language :: Python :: 3.10',
             'Programming Language :: Python :: 3.11',
             'Programming Language :: Python :: 3.12',
             'Programming Language :: Python :: 3.13',
+            'Programming Language :: Python :: 3.14',
             ],
         
         # this probably only works for setuptools, but distutils seems to 
ignore it
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/__init__.py 
new/reportlab-4.4.9/src/reportlab/__init__.py
--- old/reportlab-4.4.4/src/reportlab/__init__.py       2025-09-19 
12:35:24.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab/__init__.py       2026-01-15 
10:17:13.000000000 +0100
@@ -1,9 +1,9 @@
 #Copyright ReportLab Europe Ltd. 2000-2023
 #see license.txt for license details
 __doc__="""The Reportlab PDF generation library."""
-Version = "4.4.4"
+Version = "4.4.9"
 __version__=Version
-__date__='20250918'
+__date__='20260115'
 
 import sys, os
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/lib/randomtext.py 
new/reportlab-4.4.9/src/reportlab/lib/randomtext.py
--- old/reportlab-4.4.4/src/reportlab/lib/randomtext.py 2024-12-13 
09:46:59.000000000 +0100
+++ new/reportlab-4.4.9/src/reportlab/lib/randomtext.py 2025-09-30 
22:36:09.000000000 +0200
@@ -317,87 +317,6 @@
         newparts = []
     return format_wisdom('  '.join(output))
 
-from reportlab import rl_config
-if rl_config.invariant:
-    import random
-    #monkey patch random.randrange
-    class RLMonkeyPatchRandom(random.Random):
-        def randrange(self, start, stop=None, step=1, _int=int, 
_maxwidth=1<<random.BPF):
-            """Choose a random item from range(start, stop[, step]).
-
-            This fixes the problem with randint() which includes the
-            endpoint; in Python this is usually not what you want.
-
-            """
-
-            # This code is a bit messy to make it fast for the
-            # common case while still doing adequate error checking.
-            istart = _int(start)
-            if istart != start:
-                raise ValueError("non-integer arg 1 for randrange()")
-            if stop is None:
-                if istart > 0:
-                    if istart >= _maxwidth:
-                        return self._randbelow(istart)
-                    return _int(self.random() * istart)
-                raise ValueError("empty range for randrange()")
-
-            # stop argument supplied.
-            istop = _int(stop)
-            if istop != stop:
-                raise ValueError("non-integer stop for randrange()")
-            width = istop - istart
-            if step == 1 and width > 0:
-                # Note that
-                #     int(istart + self.random()*width)
-                # instead would be incorrect.  For example, consider istart
-                # = -2 and istop = 0.  Then the guts would be in
-                # -2.0 to 0.0 exclusive on both ends (ignoring that random()
-                # might return 0.0), and because int() truncates toward 0, the
-                # final result would be -1 or 0 (instead of -2 or -1).
-                #     istart + int(self.random()*width)
-                # would also be incorrect, for a subtler reason:  the RHS
-                # can return a long, and then randrange() would also return
-                # a long, but we're supposed to return an int (for backward
-                # compatibility).
-
-                if width >= _maxwidth:
-                    return _int(istart + self._randbelow(width))
-                return _int(istart + _int(self.random()*width))
-            if step == 1:
-                raise ValueError("empty range for randrange() (%d,%d, %d)" % 
(istart, istop, width))
-
-            # Non-unit step argument supplied.
-            istep = _int(step)
-            if istep != step:
-                raise ValueError("non-integer step for randrange()")
-            if istep > 0:
-                n = (width + istep - 1) // istep
-            elif istep < 0:
-                n = (width + istep + 1) // istep
-            else:
-                raise ValueError("zero step for randrange()")
-
-            if n <= 0:
-                raise ValueError("empty range for randrange()")
-
-            if n >= _maxwidth:
-                return istart + istep*self._randbelow(n)
-            return istart + istep*_int(self.random() * n)
-        def choice(self, seq):
-            """Choose a random element from a non-empty sequence."""
-            return seq[int(self.random() * len(seq))]
-    random.Random.randrange = RLMonkeyPatchRandom.randrange
-    random.Random.choice = RLMonkeyPatchRandom.choice
-    random.randrange = random._inst.randrange
-    random.choice = random._inst.choice
-    del RLMonkeyPatchRandom
-    if not getattr(rl_config,'_random',None):
-        rl_config._random = 1
-        random.seed(2342471922)
-    del random
-del rl_config
-
 def randomText(theme=STARTUP, sentences=5):
     #this may or may not be appropriate in your company
     if type(theme)==type(''):
@@ -425,7 +344,11 @@
     return output
 
 if __name__=='__main__':
-    import sys
+    import sys, random
+    from reportlab.rl_config import invariant as rl_invariant
+    if rl_invariant:
+        random.seed(1854640162)
+        print(f'{" ".join((str(random.randrange(100)) for _ in range(10)))}')
     argv = sys.argv[1:]
     if argv:
         theme = argv.pop(0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/lib/testutils.py 
new/reportlab-4.4.9/src/reportlab/lib/testutils.py
--- old/reportlab-4.4.4/src/reportlab/lib/testutils.py  2025-03-26 
10:06:40.000000000 +0100
+++ new/reportlab-4.4.9/src/reportlab/lib/testutils.py  2025-09-30 
22:47:45.000000000 +0200
@@ -14,8 +14,12 @@
 
 import sys, os, fnmatch, re, functools
 from configparser import ConfigParser
-import unittest
+import unittest, random
 from reportlab.lib.utils import isCompactDistro, __rl_loader__, rl_isdir, 
asUnicode
+from reportlab.rl_config import invariant as rl_invariant
+
+def invariantSeed(n):
+    if rl_invariant: random.seed(n)
 
 def haveRenderPM():
     from reportlab.graphics.renderPM import _getPMBackend, RenderPMError
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/lib/utils.py 
new/reportlab-4.4.9/src/reportlab/lib/utils.py
--- old/reportlab-4.4.4/src/reportlab/lib/utils.py      2025-07-18 
14:07:47.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab/lib/utils.py      2026-01-14 
12:49:17.000000000 +0100
@@ -116,10 +116,10 @@
         return str(x).encode(enc)
 
 def encode_label(args):
-    return base64_encodebytes(pickle.dumps(args)).strip().decode('latin1')
+    return 
base64_encodebytes(ascii(args).encode('ascii')).strip().decode('ascii')
 
 def decode_label(label):
-    return pickle.loads(base64_decodebytes(label.encode('latin1')))
+    return 
literal_eval(base64_decodebytes(label.encode('ascii')).decode('ascii'))
 
 def rawUnicode(s):
     '''converts first 256 unicodes 1-1'''
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/pdfbase/pdfdoc.py 
new/reportlab-4.4.9/src/reportlab/pdfbase/pdfdoc.py
--- old/reportlab-4.4.4/src/reportlab/pdfbase/pdfdoc.py 2025-07-18 
13:51:47.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab/pdfbase/pdfdoc.py 2025-12-09 
11:32:41.000000000 +0100
@@ -186,7 +186,7 @@
         digest = self.signature.digest()
         doc = DummyDoc()
         IDs = PDFText(digest,enc='raw').format(doc)
-        self._ID = (b'\n['+IDs+IDs+b']\n% ReportLab generated PDF document -- 
digest (http://www.reportlab.com)\n')
+        self._ID = (b'\n['+IDs+IDs+b']\n% ReportLab generated PDF document -- 
digest (opensource)\n')
         return self._ID
 
     def SaveToFile(self, filename, canvas):
@@ -891,7 +891,7 @@
         # any other encoding, and we'll be able to tell if something
         # has run our PDF files through a dodgy Unicode conversion.
         self.add((pdfdocEnc("%%PDF-%s.%s" % pdfVersion) +
-            b'\n%\223\214\213\236 ReportLab Generated PDF document 
http://www.reportlab.com\n'
+            b'\n%\223\214\213\236 ReportLab Generated PDF document 
(opensource)\n'
             ))
 
     def closeOrReset(self):
@@ -1549,13 +1549,13 @@
         return sum(counts)  #used to be: return reduce(add, counts)
     return 1
 
-_default_producer = "ReportLab PDF Library - www.reportlab.com"
+_default_producer = "ReportLab PDF Library - (opensource)"
 class PDFInfo(PDFObject):
     """PDF documents can have basic information embedded, viewable from
     File | Document Info in Acrobat Reader.  If this is wrong, you get
     Postscript errors while printing, even though it does not print."""
     producer = _default_producer
-    creator = "ReportLab PDF Library - www.reportlab.com"
+    creator = "anonymous"
     title = "untitled"
     author = "anonymous"
     subject = "unspecified"
@@ -1617,7 +1617,7 @@
         d.update(kw)
         for name in self.required:
             if name not in d:
-                raise ValueError("keyword argument %s missing" % name)
+                raise ValueError(f"keyword argument {name} missing")
         d = self.cvtdict(d,escape=escape)
         permitted = self.permitted
         for name in d.keys():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/pdfgen/canvas.py 
new/reportlab-4.4.9/src/reportlab/pdfgen/canvas.py
--- old/reportlab-4.4.4/src/reportlab/pdfgen/canvas.py  2025-07-18 
13:51:47.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab/pdfgen/canvas.py  2026-01-15 
10:16:10.000000000 +0100
@@ -369,6 +369,7 @@
         self.state_stack = []
 
         self.setEncrypt(encrypt)
+        self._namedCB = {}  #named callbacks
 
     def setEncrypt(self, encrypt):
         '''
@@ -2010,5 +2011,11 @@
         self.rect(x1,y1,width,height)
         if ss: self.restoreState()
 
+    def setNamedCB(self, name, cb):
+        self._namedCB[name] = cb
+
+    def getNamedCB(self,name):
+        return self._namedCB.get(name,None)
+
 if __name__ == '__main__':
     print('For test scripts, look in tests')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/reportlab-4.4.4/src/reportlab/platypus/doctemplate.py 
new/reportlab-4.4.9/src/reportlab/platypus/doctemplate.py
--- old/reportlab-4.4.4/src/reportlab/platypus/doctemplate.py   2025-08-01 
13:03:21.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab/platypus/doctemplate.py   2026-01-15 
09:24:08.000000000 +0100
@@ -398,7 +398,7 @@
 
     def onPage(self,canv,doc):
         '''this will be called at the start of the page'''
-        setattr(canv,self.name,self)    #push ourselves onto the canvas
+        canv.setNamedCB(self.name,self) #push ourselves onto the canvas
         self.reset()
 
     def onPageEnd(self,canv,doc):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/platypus/flowables.py 
new/reportlab-4.4.9/src/reportlab/platypus/flowables.py
--- old/reportlab-4.4.4/src/reportlab/platypus/flowables.py     2025-09-10 
14:02:39.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab/platypus/flowables.py     2025-12-02 
10:51:09.000000000 +0100
@@ -1287,7 +1287,10 @@
         H = 0
         pS = sB = 0
         atTop = 1
-        F = self._getContent(content)
+        if isinstance(self,ListFlowable):
+            F = self._getContent() if hasattr(self,'_flowables') else 
self._list_content
+        else:
+            F = self._getContent(content)
         for i,f in enumerate(F):
             if hasattr(f,'frameAction'):
                 from reportlab.platypus.doctemplate import Indenter
@@ -2222,7 +2225,7 @@
         self.value = value
         self.first= first
 
-class ListFlowable(_Container,Flowable):
+class ListFlowable(_Container,Flowable,_FindSplitterMixin):
     _numberStyles = '1aAiI'
     def __init__(self,
                     flowables,  #the initial flowables
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/platypus/paragraph.py 
new/reportlab-4.4.9/src/reportlab/platypus/paragraph.py
--- old/reportlab-4.4.4/src/reportlab/platypus/paragraph.py     2025-08-05 
10:35:01.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab/platypus/paragraph.py     2026-01-15 
09:23:10.000000000 +0100
@@ -330,9 +330,11 @@
                 if kind=='anchor':
                     tx._canvas.bookmarkHorizontal(name,cur_x,cur_y+leading)
                 else:
-                    func = getattr(tx._canvas,name,None)
+                    func = tx._canvas.getNamedCB(name)
                     if not func:
                         raise AttributeError("Missing %s callback attribute 
'%s'" % (kind,name))
+                    #with open('/tmp/dbg.txt','a') as _:
+                    #   print(f'{kind=} {name=} {func=}',file=_)
                     
tx._canvas._curr_tx_info=dict(tx=tx,cur_x=cur_x,cur_y=cur_y,leading=leading,xs=tx.XtraState)
                     try:
                         func(tx._canvas,kind,getattr(cbDefn,'label',None))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/reportlab-4.4.4/src/reportlab/platypus/tableofcontents.py 
new/reportlab-4.4.9/src/reportlab/platypus/tableofcontents.py
--- old/reportlab-4.4.4/src/reportlab/platypus/tableofcontents.py       
2024-12-13 09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/src/reportlab/platypus/tableofcontents.py       
2026-01-15 09:20:27.000000000 +0100
@@ -249,7 +249,7 @@
                 dot = ''
             if self.formatter: page = self.formatter(page)
             drawPageNumbers(canvas, style, [(page, key)], availWidth, 
availHeight, dot)
-        self.canv.drawTOCEntryEnd = drawTOCEntryEnd
+        self.canv.setNamedCB('drawTOCEntryEnd',drawTOCEntryEnd)
 
         tableData = []
         for (level, text, pageNum, key) in _tempEntries:
@@ -377,7 +377,7 @@
         def newcanvasmaker(*args, **kwargs):
             from reportlab.pdfgen import canvas
             c = canvasmaker(*args, **kwargs)
-            setattr(c,self.name,self)
+            c.setNamedCB(self.name,self)
             return c
 
         return newcanvasmaker
@@ -437,7 +437,7 @@
             style = self.getLevelStyle(leveloffset)
             pages = [(p[1],k) for p,k in sorted(decode_label(label))]
             drawPageNumbers(canvas, style, pages, availWidth, availHeight, 
self.dot)
-        self.canv.drawIndexEntryEnd = drawIndexEntryEnd
+        self.canv.setNamedCB('drawIndexEntryEnd',drawIndexEntryEnd)
 
         alpha = ''
         tableData = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab/platypus/tables.py 
new/reportlab-4.4.9/src/reportlab/platypus/tables.py
--- old/reportlab-4.4.4/src/reportlab/platypus/tables.py        2025-09-18 
10:03:40.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab/platypus/tables.py        2025-12-21 
11:57:02.000000000 +0100
@@ -937,7 +937,7 @@
                 #transfer percentages to the defined cols
                 d = []
                 for colNo, w in minimums.items():
-                    if w.endswith('%'):
+                    if isinstance(w,str) and w.endswith('%'):
                         W[colNo] = w = availWidth*float(w[:-1])/percentTotal
                         totalDefined += w
                         d.append(colNo)
@@ -1460,7 +1460,7 @@
         if isinstance(value, (tuple, list)):
             newCellContent = []
             postponedContent = []
-            split = False
+            flowable_split_attempted = False
             FH = []
             cellHeight = self._listCellGeom(value, width, style,H=FH)[1]
 
@@ -1471,41 +1471,39 @@
 
             for flowable,_fh in zip(value,FH):
                 flowable_height = getattr(flowable,'height',_fh)
-                if split:
-                    if flowable_height <= height1:
-                        postponedContent.append(flowable)
-                        # Shrink the available height:
-                        height1 -= flowable_height
-                    else:
-                        # The content doesn't fit after the split:
-                        return []
+                if flowable_split_attempted:
+                    # the flowable split may have failed, but we made some 
progress,
+                    # so postpone everything else and hope it can be 
split/wrapped later on
+                    postponedContent.append(flowable)
                 elif usedHeight + flowable_height + flowable.getSpaceBefore() 
<= height0:
                     newCellContent.append(flowable)
                     usedHeight += flowable_height + flowable.getSpaceBefore() 
+ flowable.getSpaceAfter()
                 else:
                     # This is where we need to split
-                    splits = flowable.split(width, 
height0-usedHeight-flowable.getSpaceBefore())
-                    if splits:
-                        newCellContent.append(splits[0])
-                        postponedContent.append(splits[1])
+                    splitHeight = height0-usedHeight-flowable.getSpaceBefore()
+                    splits = None
+                    if hasattr(flowable,'_findSplit'):
+                        _w,_H, S0, S1 = 
flowable._findSplit(getattr(self,'canv',None),width,splitHeight,mergeSpace=1,obj=None,content=None,paraFix=True)
+                        if S0 and S1:
+                            splits = S0
+                            newCellContent.extend(S0)
+                            postponedContent.extend(S1)
                     else:
-                        # We couldn't split this flowable at the desired
-                        # point. If we already has added previous paragraphs
-                        # to the content, just add everything after the split.
-                        # Also try adding it after the split if valign isn't 
TOP
-                        if newCellContent or style.valign != "TOP":
-                            if flowable_height <= height1:
-                                postponedContent.append(flowable)
-                                # Shrink the available height:
-                                height1 -= flowable_height
-                            else:
-                                # The content doesn't fit after the split:
-                                return []
-                        else:
-                            # We could not split this, so we fail:
+                        splits = flowable.split(width, splitHeight)
+                        if splits:
+                            newCellContent.append(splits[0])
+                            postponedContent.append(splits[1])
+                    if not splits:
+                        # We couldn't split this flowable at the desired point
+                        if (not newCellContent) and style.valign == "TOP":
+                            # This is the first flowable in the cell, and the 
cell
+                            # is top-aligned - since splitting the flowable 
failed,
+                            # splitting the cell has failed.
                             return []
 
-                    split = True
+                        # postpone this flowable, and hope we can wrap/split 
later
+                        postponedContent.append(flowable)
+                    flowable_split_attempted = True
 
             return (tuple(newCellContent), tuple(postponedContent))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab.egg-info/PKG-INFO 
new/reportlab-4.4.9/src/reportlab.egg-info/PKG-INFO
--- old/reportlab-4.4.4/src/reportlab.egg-info/PKG-INFO 2025-09-19 
12:38:42.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab.egg-info/PKG-INFO 2026-01-15 
10:23:11.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: reportlab
-Version: 4.4.4
+Version: 4.4.9
 Summary: The Reportlab Toolkit
 Home-page: https://www.reportlab.com/
 Author: Andy Robinson, Robin Becker, the ReportLab team and the community
@@ -12,11 +12,11 @@
 Classifier: Topic :: Printing
 Classifier: Topic :: Text Processing :: Markup
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
 Requires-Python: >=3.9,<4
 License-File: LICENSE
 Requires-Dist: pillow>=9.0.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/src/reportlab.egg-info/SOURCES.txt 
new/reportlab-4.4.9/src/reportlab.egg-info/SOURCES.txt
--- old/reportlab-4.4.4/src/reportlab.egg-info/SOURCES.txt      2025-09-19 
12:38:42.000000000 +0200
+++ new/reportlab-4.4.9/src/reportlab.egg-info/SOURCES.txt      2026-01-15 
10:23:11.000000000 +0100
@@ -810,6 +810,58 @@
 tests/charts-out/test_graphics_images_alpha_test8.png
 tests/render-out/410.png
 tests/render-out/410.py
+tests/render-out/Drawing01.gif
+tests/render-out/Drawing01.jpg
+tests/render-out/Drawing01.png
+tests/render-out/Drawing01.py
+tests/render-out/Drawing02.gif
+tests/render-out/Drawing02.jpg
+tests/render-out/Drawing02.png
+tests/render-out/Drawing02.py
+tests/render-out/Drawing03.gif
+tests/render-out/Drawing03.jpg
+tests/render-out/Drawing03.png
+tests/render-out/Drawing03.py
+tests/render-out/Drawing04.gif
+tests/render-out/Drawing04.jpg
+tests/render-out/Drawing04.png
+tests/render-out/Drawing04.py
+tests/render-out/Drawing05.gif
+tests/render-out/Drawing05.jpg
+tests/render-out/Drawing05.png
+tests/render-out/Drawing05.py
+tests/render-out/Drawing06.gif
+tests/render-out/Drawing06.jpg
+tests/render-out/Drawing06.png
+tests/render-out/Drawing06.py
+tests/render-out/Drawing07.gif
+tests/render-out/Drawing07.jpg
+tests/render-out/Drawing07.png
+tests/render-out/Drawing07.py
+tests/render-out/Drawing08.gif
+tests/render-out/Drawing08.jpg
+tests/render-out/Drawing08.png
+tests/render-out/Drawing08.py
+tests/render-out/Drawing09.gif
+tests/render-out/Drawing09.jpg
+tests/render-out/Drawing09.png
+tests/render-out/Drawing09.py
+tests/render-out/Drawing10.gif
+tests/render-out/Drawing10.jpg
+tests/render-out/Drawing10.png
+tests/render-out/Drawing10.py
+tests/render-out/Drawing11.gif
+tests/render-out/Drawing11.jpg
+tests/render-out/Drawing11.png
+tests/render-out/Drawing11.py
+tests/render-out/Drawing12.gif
+tests/render-out/Drawing12.jpg
+tests/render-out/Drawing12.png
+tests/render-out/Drawing12.py
+tests/render-out/Drawing14.gif
+tests/render-out/Drawing14.jpg
+tests/render-out/Drawing14.png
+tests/render-out/Drawing14.py
 tests/render-out/autoclose-none.png
 tests/render-out/autoclose-none.py
 tests/render-out/autoclose-pdf.png
Binary files old/reportlab-4.4.4/tests/render-out/Drawing01.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing01.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing01.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing01.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing01.png and 
new/reportlab-4.4.9/tests/render-out/Drawing01.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing01.py 
new/reportlab-4.4.9/tests/render-out/Drawing01.py
--- old/reportlab-4.4.4/tests/render-out/Drawing01.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing01.py   2026-01-15 
10:19:17.000000000 +0100
@@ -0,0 +1,15 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
Rect, String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               
self.add(Rect(50,50,300,100,rx=0,ry=0,fillColor=Color(1,1,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               self.add(String(180,100,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(1,0,0,1)))
+               self.add(String(180,86,b'Special characters 
\xc2\xa2\xc2\xa9\xc2\xae\xc2\xa3\xce\xb1\xce\xb2',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(1,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing02.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing02.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing02.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing02.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing02.png and 
new/reportlab-4.4.9/tests/render-out/Drawing02.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing02.py 
new/reportlab-4.4.9/tests/render-out/Drawing02.py
--- old/reportlab-4.4.4/tests/render-out/Drawing02.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing02.py   2026-01-15 
10:19:17.000000000 +0100
@@ -0,0 +1,14 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, Line
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               
self.add(Line(50,50,300,100,strokeColor=Color(0,0,1,1),strokeWidth=14.17323,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Line(50,100,300,50,strokeColor=Color(0,0,1,1),strokeWidth=14.17323,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=[5,10,15],strokeOpacity=None))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing03.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing03.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing03.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing03.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing03.png and 
new/reportlab-4.4.9/tests/render-out/Drawing03.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing03.py 
new/reportlab-4.4.9/tests/render-out/Drawing03.py
--- old/reportlab-4.4.4/tests/render-out/Drawing03.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing03.py   2026-01-15 
10:19:17.000000000 +0100
@@ -0,0 +1,19 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               self.add(String(34,34,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=12,fillColor=Color(0,0,0,1)))
+               self.add(String(42,42,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=16,fillColor=Color(0,0,0,1)))
+               self.add(String(50,50,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=20,fillColor=Color(0,0,0,1)))
+               self.add(String(58,58,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=24,fillColor=Color(0,0,0,1)))
+               self.add(String(66,66,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=28,fillColor=Color(0,0,0,1)))
+               self.add(String(74,74,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=32,fillColor=Color(0,0,0,1)))
+               self.add(String(150,150,'Hello 
World',textAnchor='start',fontName='Vera',fontSize=36,fillColor=Color(0,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing04.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing04.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing04.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing04.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing04.png and 
new/reportlab-4.4.9/tests/render-out/Drawing04.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing04.py 
new/reportlab-4.4.9/tests/render-out/Drawing04.py
--- old/reportlab-4.4.4/tests/render-out/Drawing04.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing04.py   2026-01-15 
10:19:18.000000000 +0100
@@ -0,0 +1,15 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               self.add(String(50,50,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,1,1)))
+               self.add(String(80,80,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(1,1,0,1)))
+               self.add(String(110,110,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(1,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing05.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing05.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing05.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing05.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing05.png and 
new/reportlab-4.4.9/tests/render-out/Drawing05.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing05.py 
new/reportlab-4.4.9/tests/render-out/Drawing05.py
--- old/reportlab-4.4.4/tests/render-out/Drawing05.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing05.py   2026-01-15 
10:19:18.000000000 +0100
@@ -0,0 +1,19 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
Line, String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               
self.add(Line(250,10,250,190,strokeColor=Color(.501961,.501961,.501961,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               self.add(String(250,130,'Hello 
World',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1)))
+               
self.add(String(50,130,'start:',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1)))
+               self.add(String(250,100,'Hello 
World',textAnchor='middle',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1)))
+               
self.add(String(50,100,'middle:',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1)))
+               self.add(String(250,70,'Hello 
World',textAnchor='end',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1)))
+               
self.add(String(50,70,'end:',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing06.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing06.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing06.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing06.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing06.png and 
new/reportlab-4.4.9/tests/render-out/Drawing06.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing06.py 
new/reportlab-4.4.9/tests/render-out/Drawing06.py
--- old/reportlab-4.4.4/tests/render-out/Drawing06.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing06.py   2026-01-15 
10:19:18.000000000 +0100
@@ -0,0 +1,23 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
Line, Circle, Wedge, PolyLine, Polygon, Ellipse, Rect, String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               
self.add(Line(10,10,390,190,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Circle(100,100,20,fillColor=Color(0,.501961,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Circle(200,100,40,fillColor=Color(0,.501961,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Circle(300,100,30,fillColor=Color(0,.501961,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Wedge(330,100,40,-10,40,yradius=None,annular=False,fillColor=Color(0,.501961,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(PolyLine(points=[120,10,130,20,140,10,150,20,160,10,170,20,180,10,190,20,200,10],strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None,fillColor=Color(0,.501961,0,1)))
+               
self.add(Polygon(points=[300,20,350,20,390,80,300,75,330,40],fillColor=Color(0,.501961,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Ellipse(50,150,40,20,fillColor=Color(0,.501961,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Rect(120,150,60,30,rx=0,ry=0,fillColor=Color(0,.501961,0,1),fillOpacity=None,strokeColor=Color(1,1,0,1),strokeWidth=10,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Rect(220,150,60,30,rx=10,ry=10,fillColor=Color(0,.501961,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               self.add(String(10,50,'Basic 
Shapes',textAnchor='start',fontName='Helvetica',fontSize=10,fillColor=Color(0,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing07.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing07.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing07.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing07.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing07.png and 
new/reportlab-4.4.9/tests/render-out/Drawing07.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing07.py 
new/reportlab-4.4.9/tests/render-out/Drawing07.py
--- old/reportlab-4.4.4/tests/render-out/Drawing07.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing07.py   2026-01-15 
10:19:18.000000000 +0100
@@ -0,0 +1,66 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
Line, String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               v0=self._nn(Group())
+               v0.transform = (1,0,0,1,10,10)
+               
v0.add(Line(0,0,100,0,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,0,0,50,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,10,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,20,10,20,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,30,10,30,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,40,10,40,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(10,0,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(20,0,20,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(30,0,30,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(40,0,40,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(50,0,50,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(60,0,60,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(70,0,70,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(80,0,80,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(90,0,90,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(String(20,35,'Axes',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1),fill=Color(0,0,0,1)))
+               v0=self._nn(Group())
+               v0.transform = (.965926,.258819,-0.258819,.965926,150,10)
+               
v0.add(Line(0,0,100,0,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,0,0,50,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,10,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,20,10,20,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,30,10,30,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,40,10,40,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(10,0,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(20,0,20,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(30,0,30,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(40,0,40,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(50,0,50,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(60,0,60,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(70,0,70,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(80,0,80,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(90,0,90,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(String(20,35,'Axes',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1),fill=Color(0,0,0,1)))
+               v0=self._nn(Group())
+               v0.transform = (.866025,.5,-0.5,.866025,300,10)
+               
v0.add(Line(0,0,100,0,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,0,0,50,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,10,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,20,10,20,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,30,10,30,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,40,10,40,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(10,0,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(20,0,20,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(30,0,30,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(40,0,40,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(50,0,50,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(60,0,60,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(70,0,70,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(80,0,80,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(90,0,90,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(String(20,35,'Axes',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1),fill=Color(0,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing08.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing08.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing08.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing08.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing08.png and 
new/reportlab-4.4.9/tests/render-out/Drawing08.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing08.py 
new/reportlab-4.4.9/tests/render-out/Drawing08.py
--- old/reportlab-4.4.4/tests/render-out/Drawing08.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing08.py   2026-01-15 
10:19:19.000000000 +0100
@@ -0,0 +1,84 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
Line, String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               v0=self._nn(Group())
+               v0.transform = (1,0,0,1,10,10)
+               
v0.add(Line(0,0,100,0,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,0,0,50,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,10,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,20,10,20,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,30,10,30,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,40,10,40,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(10,0,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(20,0,20,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(30,0,30,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(40,0,40,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(50,0,50,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(60,0,60,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(70,0,70,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(80,0,80,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(90,0,90,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(String(20,35,'Axes',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1),fill=Color(0,0,0,1)))
+               v0=self._nn(Group())
+               v0.transform = (1,0,0,2,150,10)
+               
v0.add(Line(0,0,100,0,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,0,0,50,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,10,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,20,10,20,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,30,10,30,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,40,10,40,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(10,0,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(20,0,20,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(30,0,30,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(40,0,40,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(50,0,50,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(60,0,60,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(70,0,70,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(80,0,80,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(90,0,90,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(String(20,35,'Axes',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1),fill=Color(0,0,0,1)))
+               v0=self._nn(Group())
+               v0.transform = (2,0,0,1,10,125)
+               
v0.add(Line(0,0,100,0,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,0,0,50,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,10,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,20,10,20,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,30,10,30,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,40,10,40,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(10,0,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(20,0,20,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(30,0,30,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(40,0,40,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(50,0,50,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(60,0,60,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(70,0,70,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(80,0,80,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(90,0,90,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(String(20,35,'Axes',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1),fill=Color(0,0,0,1)))
+               v0=self._nn(Group())
+               v0.transform = (1,0,.57735,1,250,125)
+               
v0.add(Line(0,0,100,0,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,0,0,50,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,10,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,20,10,20,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,30,10,30,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(0,40,10,40,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(10,0,10,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(20,0,20,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(30,0,30,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(40,0,40,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(50,0,50,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(60,0,60,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(70,0,70,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(80,0,80,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(90,0,90,10,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(String(20,35,'Axes',textAnchor='start',fontName='Times-Roman',fontSize=10,fillColor=Color(0,0,0,1),fill=Color(0,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing09.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing09.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing09.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing09.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing09.png and 
new/reportlab-4.4.9/tests/render-out/Drawing09.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing09.py 
new/reportlab-4.4.9/tests/render-out/Drawing09.py
--- old/reportlab-4.4.4/tests/render-out/Drawing09.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing09.py   2026-01-15 
10:19:19.000000000 +0100
@@ -0,0 +1,18 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
String, Rect
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               self.add(String(20,20,'I should be totally horizontal and 
enclosed in a 
box',textAnchor='start',fontName='Times-Roman',fontSize=12,fillColor=Color(0,0,0,1)))
+               
self.add(Rect(18,18,249.64,16,rx=0,ry=0,fillColor=None,fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               v0=self._nn(Group())
+               v0.transform = (.965926,.258819,-0.258819,.965926,0,50)
+               v0.add(String(20,20,'I should slope up by 15 degrees, so my 
right end is higher than my 
left',textAnchor='start',fontName='Times-Roman',fontSize=12,fillColor=Color(0,0,0,1)))
+               
v0.add(Rect(18,18,342.64,16,rx=0,ry=0,fillColor=None,fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing10.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing10.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing10.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing10.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing10.png and 
new/reportlab-4.4.9/tests/render-out/Drawing10.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing10.py 
new/reportlab-4.4.9/tests/render-out/Drawing10.py
--- old/reportlab-4.4.4/tests/render-out/Drawing10.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing10.py   2026-01-15 
10:19:19.000000000 +0100
@@ -0,0 +1,32 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
Rect, String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               
self.add(Rect(0,0,100,20,rx=0,ry=0,fillColor=Color(1,1,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               self.add(String(5,5,'Text in the 
box',textAnchor='start',fontName='Times-Roman',fontSize=12,fillColor=Color(0,0,0,1)))
+               v0=self._nn(Group())
+               v0.transform = (1,0,0,1,25,25)
+               
v0.add(Rect(0,0,100,20,rx=0,ry=0,fillColor=Color(1,1,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               v0.add(String(5,5,'Text in the 
box',textAnchor='start',fontName='Times-Roman',fontSize=12,fillColor=Color(0,0,0,1)))
+               v0=self._nn(Group())
+               v0.transform = (1,0,0,1,25,25)
+               v1=v0._nn(Group())
+               v1.transform = (1,0,0,1,25,25)
+               
v1.add(Rect(0,0,100,20,rx=0,ry=0,fillColor=Color(1,1,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               v1.add(String(5,5,'Text in the 
box',textAnchor='start',fontName='Times-Roman',fontSize=12,fillColor=Color(0,0,0,1)))
+               v0=self._nn(Group())
+               v0.transform = (1,0,0,1,25,25)
+               v1=v0._nn(Group())
+               v1.transform = (1,0,0,1,25,25)
+               v2=v1._nn(Group())
+               v2.transform = (1,0,0,1,25,25)
+               
v2.add(Rect(0,0,100,20,rx=0,ry=0,fillColor=Color(1,1,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               v2.add(String(5,5,'Text in the 
box',textAnchor='start',fontName='Times-Roman',fontSize=12,fillColor=Color(0,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing11.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing11.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing11.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing11.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing11.png and 
new/reportlab-4.4.9/tests/render-out/Drawing11.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing11.py 
new/reportlab-4.4.9/tests/render-out/Drawing11.py
--- old/reportlab-4.4.4/tests/render-out/Drawing11.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing11.py   2026-01-15 
10:19:20.000000000 +0100
@@ -0,0 +1,26 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
Circle, Ellipse, PolyLine, Line
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               
self.add(Circle(100,100,10,fillColor=Color(1,0,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=.526316,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Ellipse(96.66667,103.3333,.666667,2,fillColor=Color(0,0,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=.526316,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Ellipse(103.3333,103.3333,.666667,2,fillColor=Color(0,0,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=.526316,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(PolyLine(points=[93.73538,97.71987,93.77613,97.61088,93.81877,97.50262,93.8633,97.39513,93.9097,97.28842,93.95795,97.18254,94.00804,97.07753,94.05996,96.9734,94.11368,96.87019,94.1692,96.76794,94.2265,96.66667,94.28555,96.56641,94.34635,96.4672,94.40886,96.36907,94.47308,96.27205,94.53899,96.17616,94.60655,96.08143,94.67576,95.9879,94.74659,95.89559,94.81903,95.80453,94.89304,95.71475,94.9686,95.62627,95.0457,95.53913,95.12431,95.45334,95.2044,95.36894,95.28595,95.28595,95.36894,95.2044,95.45334,95.12431,95.53913,95.0457,95.62627,94.9686,95.71475,94.89304,95.80453,94.81903,95.89559,94.74659,95.9879,94.67576,96.08143,94.60655,96.17616,94.53899,96.27205,94.47308,96.36907,94.40886,96.4672,94.34635,96.56641,94.28555,96.66667,94.2265,96.76794,94.1692,96.87019,94.11368,96.9734,94.05996,97.07753,94.00804,97.18254,93.95795,97.28842,93.9097,97.39513,93.8633,97.50262,93.81877,97.61088,93.77613,97.71987,93.73538,97.82955,93.69654,97.93989,93.65962,98.05086,93.62463,98.16242,93.59159
 
,98.27454,93.56049,98.38719,93.53136,98.50033,93.5042,98.61392,93.47902,98.72794,93.45582,98.84235,93.43461,98.9571,93.41541,99.07218,93.39821,99.18754,93.38303,99.30314,93.36985,99.41896,93.3587,99.53496,93.34957,99.65109,93.34247,99.76734,93.33739,99.88365,93.33435,100,93.33333,100.1163,93.33435,100.2327,93.33739,100.3489,93.34247,100.465,93.34957,100.581,93.3587,100.6969,93.36985,100.8125,93.38303,100.9278,93.39821,101.0429,93.41541,101.1577,93.43461,101.2721,93.45582,101.3861,93.47902,101.4997,93.5042,101.6128,93.53136,101.7255,93.56049,101.8376,93.59159,101.9491,93.62463,102.0601,93.65962,102.1705,93.69654,102.2801,93.73538,102.3891,93.77613,102.4974,93.81877,102.6049,93.8633,102.7116,93.9097,102.8175,93.95795,102.9225,94.00804,103.0266,94.05996,103.1298,94.11368,103.2321,94.1692,103.3333,94.2265,103.4336,94.28555,103.5328,94.34635,103.6309,94.40886,103.728,94.47308,103.8238,94.53899,103.9186,94.60655,104.0121,94.67576,104.1044,94.74659,104.1955,94.81903,104.2853,94.89304,104.3
 
737,94.9686,104.4609,95.0457,104.5467,95.12431,104.6311,95.2044,104.714,95.28595,104.7956,95.36894,104.8757,95.45334,104.9543,95.53913,105.0314,95.62627,105.107,95.71475,105.181,95.80453,105.2534,95.89559,105.3242,95.9879,105.3934,96.08143,105.461,96.17616,105.5269,96.27205,105.5911,96.36907,105.6537,96.4672,105.7144,96.56641,105.7735,96.66667,105.8308,96.76794,105.8863,96.87019,105.94,96.9734,105.992,97.07753,106.0421,97.18254,106.0903,97.28842,106.1367,97.39513,106.1812,97.50262,106.2239,97.61088,106.2646,97.71987],strokeColor=Color(0,0,0,1),strokeWidth=.526316,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None,fillColor=Color(0,0,0,1)))
+               
self.add(Line(90,100,110,100,strokeColor=Color(0,.501961,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
self.add(Line(100,90,100,110,strokeColor=Color(0,.501961,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               v0=self._nn(Group())
+               v0.transform = (2,0,0,2,100,-100)
+               
v0.add(Circle(100,100,10,fillColor=Color(0,0,1,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=.526316,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Ellipse(96.66667,103.3333,.666667,2,fillColor=Color(0,0,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=.526316,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Ellipse(103.3333,103.3333,.666667,2,fillColor=Color(0,0,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=.526316,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(PolyLine(points=[93.73538,97.71987,93.77613,97.61088,93.81877,97.50262,93.8633,97.39513,93.9097,97.28842,93.95795,97.18254,94.00804,97.07753,94.05996,96.9734,94.11368,96.87019,94.1692,96.76794,94.2265,96.66667,94.28555,96.56641,94.34635,96.4672,94.40886,96.36907,94.47308,96.27205,94.53899,96.17616,94.60655,96.08143,94.67576,95.9879,94.74659,95.89559,94.81903,95.80453,94.89304,95.71475,94.9686,95.62627,95.0457,95.53913,95.12431,95.45334,95.2044,95.36894,95.28595,95.28595,95.36894,95.2044,95.45334,95.12431,95.53913,95.0457,95.62627,94.9686,95.71475,94.89304,95.80453,94.81903,95.89559,94.74659,95.9879,94.67576,96.08143,94.60655,96.17616,94.53899,96.27205,94.47308,96.36907,94.40886,96.4672,94.34635,96.56641,94.28555,96.66667,94.2265,96.76794,94.1692,96.87019,94.11368,96.9734,94.05996,97.07753,94.00804,97.18254,93.95795,97.28842,93.9097,97.39513,93.8633,97.50262,93.81877,97.61088,93.77613,97.71987,93.73538,97.82955,93.69654,97.93989,93.65962,98.05086,93.62463,98.16242,93.59159,9
 
8.27454,93.56049,98.38719,93.53136,98.50033,93.5042,98.61392,93.47902,98.72794,93.45582,98.84235,93.43461,98.9571,93.41541,99.07218,93.39821,99.18754,93.38303,99.30314,93.36985,99.41896,93.3587,99.53496,93.34957,99.65109,93.34247,99.76734,93.33739,99.88365,93.33435,100,93.33333,100.1163,93.33435,100.2327,93.33739,100.3489,93.34247,100.465,93.34957,100.581,93.3587,100.6969,93.36985,100.8125,93.38303,100.9278,93.39821,101.0429,93.41541,101.1577,93.43461,101.2721,93.45582,101.3861,93.47902,101.4997,93.5042,101.6128,93.53136,101.7255,93.56049,101.8376,93.59159,101.9491,93.62463,102.0601,93.65962,102.1705,93.69654,102.2801,93.73538,102.3891,93.77613,102.4974,93.81877,102.6049,93.8633,102.7116,93.9097,102.8175,93.95795,102.9225,94.00804,103.0266,94.05996,103.1298,94.11368,103.2321,94.1692,103.3333,94.2265,103.4336,94.28555,103.5328,94.34635,103.6309,94.40886,103.728,94.47308,103.8238,94.53899,103.9186,94.60655,104.0121,94.67576,104.1044,94.74659,104.1955,94.81903,104.2853,94.89304,104.373
 
7,94.9686,104.4609,95.0457,104.5467,95.12431,104.6311,95.2044,104.714,95.28595,104.7956,95.36894,104.8757,95.45334,104.9543,95.53913,105.0314,95.62627,105.107,95.71475,105.181,95.80453,105.2534,95.89559,105.3242,95.9879,105.3934,96.08143,105.461,96.17616,105.5269,96.27205,105.5911,96.36907,105.6537,96.4672,105.7144,96.56641,105.7735,96.66667,105.8308,96.76794,105.8863,96.87019,105.94,96.9734,105.992,97.07753,106.0421,97.18254,106.0903,97.28842,106.1367,97.39513,106.1812,97.50262,106.2239,97.61088,106.2646,97.71987],strokeColor=Color(0,0,0,1),strokeWidth=.526316,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None,fillColor=Color(0,0,0,1)))
+               
v0.add(Line(90,100,110,100,strokeColor=Color(0,.501961,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               
v0.add(Line(100,90,100,110,strokeColor=Color(0,.501961,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing12.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing12.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing12.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing12.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing12.png and 
new/reportlab-4.4.9/tests/render-out/Drawing12.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing12.py 
new/reportlab-4.4.9/tests/render-out/Drawing12.py
--- old/reportlab-4.4.4/tests/render-out/Drawing12.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing12.py   2026-01-15 
10:19:20.000000000 +0100
@@ -0,0 +1,18 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
String
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               self.add(String(34,34,'Hello 
World',textAnchor='start',fontName='DarkGardenMK',fontSize=12,fillColor=Color(0,0,0,1)))
+               self.add(String(42,42,'Hello 
World',textAnchor='start',fontName='DarkGardenMK',fontSize=16,fillColor=Color(0,0,0,1)))
+               self.add(String(50,50,'Hello 
World',textAnchor='start',fontName='DarkGardenMK',fontSize=20,fillColor=Color(0,0,0,1)))
+               self.add(String(58,58,'Hello 
World',textAnchor='start',fontName='DarkGardenMK',fontSize=24,fillColor=Color(0,0,0,1)))
+               self.add(String(66,66,'Hello 
World',textAnchor='start',fontName='DarkGardenMK',fontSize=28,fillColor=Color(0,0,0,1)))
+               self.add(String(74,74,'Hello 
World',textAnchor='start',fontName='DarkGardenMK',fontSize=32,fillColor=Color(0,0,0,1)))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
Binary files old/reportlab-4.4.4/tests/render-out/Drawing14.gif and 
new/reportlab-4.4.9/tests/render-out/Drawing14.gif differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing14.jpg and 
new/reportlab-4.4.9/tests/render-out/Drawing14.jpg differ
Binary files old/reportlab-4.4.4/tests/render-out/Drawing14.png and 
new/reportlab-4.4.9/tests/render-out/Drawing14.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/render-out/Drawing14.py 
new/reportlab-4.4.9/tests/render-out/Drawing14.py
--- old/reportlab-4.4.4/tests/render-out/Drawing14.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/render-out/Drawing14.py   2026-01-15 
10:19:21.000000000 +0100
@@ -0,0 +1,14 @@
+#Autogenerated by ReportLab guiedit do not edit
+from reportlab.graphics.shapes import _DrawingEditorMixin, Drawing, Group, 
Image
+from reportlab.lib.colors import Color, CMYKColor, PCMYKColor
+
+class ExplodedDrawing_Drawing(_DrawingEditorMixin,Drawing):
+       def __init__(self,width=400,height=200,*args,**kw):
+               Drawing.__init__(self,width,height,*args,**kw)
+               self.transform = (1,0,0,1,0,0)
+               self.add(Image(0,0,None,None,<PIL.GifImagePlugin.GifImageFile 
image mode=P size=10x7 at 
0x7F8A50052710>,fillColor=Color(0,0,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+               self.add(Image(380,186,20,14,<PIL.GifImagePlugin.GifImageFile 
image mode=P size=10x7 at 
0x7F8A5015A990>,fillColor=Color(0,0,0,1),fillOpacity=None,strokeColor=Color(0,0,0,1),strokeWidth=1,strokeLineCap=0,strokeLineJoin=0,strokeMiterLimit=0,strokeDashArray=None,strokeOpacity=None))
+
+
+if __name__=="__main__": #NORUNTESTS
+       ExplodedDrawing_Drawing().save(formats=['pdf'],outDir='.',fnRoot=None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/test_paragraphs.py 
new/reportlab-4.4.9/tests/test_paragraphs.py
--- old/reportlab-4.4.4/tests/test_paragraphs.py        2025-04-17 
12:06:52.000000000 +0200
+++ new/reportlab-4.4.9/tests/test_paragraphs.py        2025-09-30 
22:21:56.000000000 +0200
@@ -3,16 +3,16 @@
 # tests some paragraph styles
 __version__='3.3.0'
 from reportlab.lib.testutils import (setOutDir,makeSuiteForClasses, outputfile,
-                                    printLocation, rlSkipUnless, haveDejaVu)
+                                    printLocation, rlSkipUnless, haveDejaVu,
+                                    invariantSeed)
 setOutDir(__name__)
-import unittest, os, random
+import unittest, os
 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
 from reportlab.pdfbase import ttfonts
@@ -74,6 +74,9 @@
 class ParagraphTestCase(unittest.TestCase):
     "Test Paragraph class (eyeball-test)."
 
+    def setUp(self):
+        invariantSeed(1854640162)
+
     def test0(self):
         """Test...
 
@@ -85,7 +88,6 @@
             2. ...
             3. ...
         """
-        if rl_invariant: random.seed(1854640162)
         story = []
         SA = story.append
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/test_platypus_breaking.py 
new/reportlab-4.4.9/tests/test_platypus_breaking.py
--- old/reportlab-4.4.4/tests/test_platypus_breaking.py 2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_breaking.py 2026-01-15 
09:02:36.000000000 +0100
@@ -3,9 +3,9 @@
 """Tests pageBreakBefore, frameBreakBefore, keepWithNext...
 """
 __version__='3.3.0'
-from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
+from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation, invariantSeed
 setOutDir(__name__)
-import sys, os, time, re, random
+import sys, os, time, re
 from reportlab.rl_config import invariant as rl_invariant
 from operator import truth
 import unittest
@@ -63,7 +63,7 @@
 def _test0(self):
     "This makes one long multi-page paragraph in test_platypus_breaking."
 
-    if rl_invariant: random.seed(1532760416)
+    invariantSeed(1532760416)
     def RT(k,theme='PYTHON',sentences=1,cache={}):
         if k not in cache:
             cache[k] = randomText(theme=theme,sentences=sentences)
@@ -175,7 +175,7 @@
             if measuring and label=='end':
                 ends.append(canv._curr_tx_info)
             annotations.append(canv._curr_tx_info)
-        setattr(canv,onDrawFuncName,_onDrawFunc)
+        canv.setNamedCB(onDrawFuncName,_onDrawFunc)
         self._state = 
(canv,style,aW,measuring,ends,annotations,errors,length_errors)
         if measuring:
             self._end = ('<ondraw name="%s" label="end"/>' % onDrawFuncName)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/test_platypus_indents.py 
new/reportlab-4.4.9/tests/test_platypus_indents.py
--- old/reportlab-4.4.4/tests/test_platypus_indents.py  2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_indents.py  2025-10-01 
11:04:07.000000000 +0200
@@ -3,7 +3,7 @@
 """Tests for context-dependent indentation
 """
 __version__='3.3.0'
-from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
+from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation, invariantSeed
 setOutDir(__name__)
 import sys, os, random
 from reportlab.rl_config import invariant as rl_invariant
@@ -65,7 +65,7 @@
 
     def test0(self):
         "IndentTestCase test0"
-        if rl_invariant: random.seed(1479316371)
+        invariantSeed(1479316371)
 
         # Build story.
         story = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/test_platypus_index.py 
new/reportlab-4.4.9/tests/test_platypus_index.py
--- old/reportlab-4.4.4/tests/test_platypus_index.py    2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_index.py    2025-09-30 
22:26:01.000000000 +0200
@@ -3,9 +3,9 @@
 """Tests for the Platypus SimpleIndex and AlphabeticIndex classes.
 """
 __version__='3.3.0'
-from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
+from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation, invariantSeed
 setOutDir(__name__)
-import sys, os, random
+import sys, os
 from reportlab.rl_config import invariant as rl_invariant
 from os.path import join, basename, splitext
 from math import sqrt
@@ -76,6 +76,9 @@
 class IndexTestCase(unittest.TestCase):
     "Test SimpleIndex classes (eyeball-test)."
 
+    def setUp(self):
+        invariantSeed(1753799561)
+
     def test0(self):
         '''
         Test case for Indexes. This will draw an index at the end of the
@@ -83,7 +86,6 @@
         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-4.4.4/tests/test_platypus_leftright.py 
new/reportlab-4.4.9/tests/test_platypus_leftright.py
--- old/reportlab-4.4.4/tests/test_platypus_leftright.py        2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_leftright.py        2025-09-30 
22:28:11.000000000 +0200
@@ -3,9 +3,9 @@
 """Tests ability to cycle through multiple page templates
 """
 __version__='3.3.0'
-from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
+from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation, invariantSeed
 setOutDir(__name__)
-import sys, os, time, random
+import sys, os, time
 from reportlab.rl_config import invariant as rl_invariant
 from operator import truth
 import unittest
@@ -86,10 +86,12 @@
 
 class LeftRightTestCase(unittest.TestCase):
     "Test multi-page splitting of paragraphs (eyeball-test)."
+    def setUp(self):
+        invariantSeed(464568862)
+
     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-4.4.4/tests/test_platypus_lists.py 
new/reportlab-4.4.9/tests/test_platypus_lists.py
--- old/reportlab-4.4.4/tests/test_platypus_lists.py    2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_lists.py    2025-09-30 
22:30:06.000000000 +0200
@@ -1,8 +1,8 @@
 from random import randint
 from xml.sax.saxutils import escape as xmlEscape
-from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
+from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation, invariantSeed
 setOutDir(__name__)
-import os,unittest, random
+import os,unittest
 from reportlab.rl_config import invariant as rl_invariant
 from reportlab.platypus import Spacer, SimpleDocTemplate, Table, TableStyle, 
ListFlowable, ListItem, \
         Paragraph, PageBreak, DDIndenter, MultiCol
@@ -59,8 +59,10 @@
 class ListsTestCase(unittest.TestCase):
     "Make documents with tables"
 
+    def setUp(self):
+        invariantSeed(888147853)
+
     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-4.4.4/tests/test_platypus_paragraphs.py 
new/reportlab-4.4.9/tests/test_platypus_paragraphs.py
--- old/reportlab-4.4.4/tests/test_platypus_paragraphs.py       2025-07-18 
14:19:09.000000000 +0200
+++ new/reportlab-4.4.9/tests/test_platypus_paragraphs.py       2026-01-15 
09:17:10.000000000 +0100
@@ -814,7 +814,7 @@
         normal.leading = 12
         normal.alignment = TA_JUSTIFY
         canv = Canvas(outputfile('test_splitJustBug.pdf'))
-        canv._odW = _odW
+        canv.setNamedCB('_odW', _odW)
         W, H = canv._pagesize
         aW = W-2*72
         aH = H-2*72
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/test_platypus_programming.py 
new/reportlab-4.4.9/tests/test_platypus_programming.py
--- old/reportlab-4.4.4/tests/test_platypus_programming.py      2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_programming.py      2025-09-30 
22:55:04.000000000 +0200
@@ -5,11 +5,13 @@
 #tests and documents Page Layout API
 __doc__="""Tests low level programming of doc templates
 """
-from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
+from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation, invariantSeed
 setOutDir(__name__)
 import sys, unittest
 class PlatypusProgrammingTestCase(unittest.TestCase):
     "test platypus programming"
+    def setUp(self):
+        invariantSeed(2103696747)
 
     def test0(self):
         from reportlab.lib.styles import ParagraphStyle
@@ -62,7 +64,6 @@
         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-4.4.4/tests/test_platypus_tables.py 
new/reportlab-4.4.9/tests/test_platypus_tables.py
--- old/reportlab-4.4.4/tests/test_platypus_tables.py   2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_tables.py   2025-12-21 
12:28:40.000000000 +0100
@@ -1161,6 +1161,32 @@
         expectedWidth = 544
         self.assertEqual(w,expectedWidth,"long paragraph as not been wrapped 
as expected")
 
+    def test_endswith_error(self):
+        '''test error reported by Andy Hagar atboom33w at gmail dot com'''
+        styles = getSampleStyleSheet()
+
+        data = [
+            ['Header 1', 'Header 2', 'Header 3'],
+            [Paragraph('Row 1, Col 1 wide data wide data wide data wide data', 
styles['Normal']), 'Row 1, Col 2 wide data wide data wide data', 'Row 1, Col 3 
wide data wide data wide data']
+        ]
+
+        story = []
+
+        colwidths = [None, "20%", None]
+        table = Table(data, colWidths=colwidths)
+        story.append(table)
+
+        pdffn = outputfile('test_endswith_error.pdf')
+        doc = SimpleDocTemplate(pdffn)
+        try:
+            doc.build(story)
+        except:
+            ok = False
+        else:
+            ok = True
+        self.assertEqual(ok,True,f'\n{pdffn} not built')
+
+
 def makeSuite():
     return makeSuiteForClasses(TablesTestCase)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/test_platypus_toc.py 
new/reportlab-4.4.9/tests/test_platypus_toc.py
--- old/reportlab-4.4.4/tests/test_platypus_toc.py      2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_toc.py      2025-09-30 
23:02:43.000000000 +0200
@@ -7,12 +7,11 @@
 in order to find out if it is 'correct'.
 """
 __version__='3.3.0'
-from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
+from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation, invariantSeed
 setOutDir(__name__)
-import sys, os
+import sys, os, random
 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
@@ -140,6 +139,9 @@
 class TocTestCase(unittest.TestCase):
     "Test TableOfContents class (eyeball-test)."
 
+    def setUp(self):
+        invariantSeed(2077179149)
+
     def test0(self):
         """Test story with TOC and a cascaded header hierarchy.
 
@@ -155,7 +157,6 @@
             ...
         """
         def doTest(rLPN=False):
-            if rl_invariant: random.seed(2077179149)
             maxLevels = 12
 
             # Create styles to be used for document headers
@@ -204,7 +205,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)
+        invariantSeed(1216902530)
         chapters = 30   #goes over one page
         
         headerStyle = makeHeaderStyle(0)
@@ -304,7 +305,7 @@
         self.assertTrue(hasattr(doc,'seq'))
 
     def test2(self):
-        if rl_invariant: random.seed(530125105)
+        invariantSeed(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-4.4.4/tests/test_platypus_xref.py 
new/reportlab-4.4.9/tests/test_platypus_xref.py
--- old/reportlab-4.4.4/tests/test_platypus_xref.py     2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_platypus_xref.py     2025-09-30 
22:34:36.000000000 +0200
@@ -3,9 +3,9 @@
 """Test long documents with indexes, tables and cross-references
 """
 __version__='3.3.0'
-from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation
+from reportlab.lib.testutils import setOutDir,makeSuiteForClasses, outputfile, 
printLocation, invariantSeed
 setOutDir(__name__)
-import sys, os, time, random
+import sys, os, time
 from reportlab.rl_config import invariant as rl_invariant
 from operator import truth
 import unittest
@@ -70,7 +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)
+    invariantSeed(1629812163)
 
     # Build story.
     story = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/reportlab-4.4.4/tests/test_table_inrowsplit.py 
new/reportlab-4.4.9/tests/test_table_inrowsplit.py
--- old/reportlab-4.4.4/tests/test_table_inrowsplit.py  2024-12-13 
09:47:00.000000000 +0100
+++ new/reportlab-4.4.9/tests/test_table_inrowsplit.py  2025-12-02 
10:51:09.000000000 +0100
@@ -15,7 +15,6 @@
 
 class TableTestCase(unittest.TestCase):
 
-
     def getDataBlock(self):
         "Helper - data for our spanned table"
         return [
@@ -483,12 +482,125 @@
         lst.extend(xlst.__self__)
         SimpleDocTemplate(outputfile('test_table_inrowsplit.pdf'), 
showBoundary=1).build(lst)
 
+    def test_list_in_row(self):
+        LOREM = """Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad 
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea 
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit 
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat 
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."""
+
+        bulleted_data = [
+            {'indent': 0, 'para': 'Lorem Ipsum is simply dummy text of the 
printing and typesetting industry.'},
+            {'indent': 0, 'para': 'Lorem Ipsum has been the industry standard 
dummy text ever since the 1500s.'},
+            {'indent': 1, 'para': '1 0 It has survived not only five 
centuries, but also the leap into electronic typesetting, remaining essentially 
unchanged.'},
+            {'indent': 1, 'para': '1 1 Contrary to popular belief, Lorem Ipsum 
is not simply random text. '+LOREM},
+
+            # pad this one out repeatedly until it breaks over the page at 
level 3
+            {'indent': 2, 'para': 'Indent level 2, with enough stuff to 
continue over the page break...'+LOREM},
+            {'indent': 2, 'para': 'This paragraph should be at the third level 
of indentation. Now let us have too much content for a page... '+LOREM},
+            {'indent': 2, 'para': '2 2 '+LOREM}, {'indent': 2, 'para': '2 3 
'+LOREM}, {'indent': 2, 'para': '2 4 '+LOREM}, {'indent': 2, 'para': '2 5 
'+LOREM},
+            {'indent': 2, 'para': '2 6 '+LOREM}, {'indent': 2, 'para': '2 7 
'+LOREM}, {'indent': 2, 'para': '2 8 '+LOREM},
+            {'indent': 1,'para': 'Back to level one.'},
+            {'indent': 1,'para': 'All the Lorem Ipsum generators on the 
Internet tend to repeat predefined chunks as necessary.'},
+            ]
+
+        class LFL(list):
+            pass
+
+        def makeUList():
+            # This holds the structured list.
+            list_stack = []
+            # Prep default style for Paragraph
+            para_style = getSampleStyleSheet()['Normal']
+            # Prep default style for ListFlowable
+            style = getSampleStyleSheet()['UnorderedList']
+            style.bulletFontSize = 12
+            style.bulletType = 'bullet'
+            style.leftIndent = 12 * 1.2
+            # Walk the list to build the nested structure
+            for next_item in bulleted_data:
+                # Get the indent value
+                indent = next_item['indent']
+                # Get the para content
+                para = next_item['para']
+                # If we have nothing, put empty list at lowest level
+                if len(list_stack) == 0:
+                    list_stack.append([])
+                # If indent value matches length of stack, start new list
+                if indent == len(list_stack):
+                    list_stack.append([])
+                    cur_list_array = list_stack[-1]
+                    cur_list_array.append(Paragraph(para, para_style))
+                # If indentation is reduced
+                elif indent < len(list_stack) - 1:
+                    i = len(list_stack) - 1
+                    while i > indent:
+                        ulist = LFL((list_stack[-1]))
+                        list_stack.pop()
+                        cur_list_array = list_stack[-1]
+                        cur_list_array.append(ulist)
+                        i = i - 1
+                    cur_list_array = list_stack[-1]
+                    cur_list_array.append(Paragraph(para, para_style))
+                # If indentation is same
+                else:
+                    cur_list_array = list_stack[-1]
+                    cur_list_array.append(Paragraph(para, para_style))
+
+            # Close remaining lists
+            ulist = None
+            while len(list_stack) > 0:
+                ulist = LFL(list_stack[-1])
+                list_stack.pop()
+                if len(list_stack) > 0:
+                    cur_list_array = list_stack[-1]
+                    cur_list_array.append(ulist)
+
+            from reportlab.platypus.flowables import _bulletNames
+            BT = list(_bulletNames.keys())
+            def findLFL(F,depth=0):
+                for i,f in enumerate(F):
+                    if isinstance(f,LFL):
+                        F[i] = findLFL(F[i],depth+1)
+                return ListFlowable(flowables=F,
+                              
style=style.clone(name=f'gen-{depth}-{i}',start=BT[depth]))
+            ulist = findLFL(ulist,depth=0)
+            return ulist
+
+        story = []
+        styGrid = TableStyle([
+                ('GRID', (0,0), (-1,-1), 0.5, colors.green),
+                ('TOPPADDING', (0,0), (-1,-1), 3),
+                ('BOTTOMPADDING', (0,0), (-1,-1), 3),
+                ('LEFTPADDING', (0,0), (-1,-1), 0),
+                ('RIGHTPADDING', (0,0), (-1,-1), 0),
+                #('VALIGN',(0,0), (-1,-1), "MIDDLE"),
+                ])
+        tbl = Table([
+            [makeUList()],
+            ],
+            splitInRow = 1,
+            style=styGrid)
+        story.append(tbl)
+
+        SimpleDocTemplate(outputfile('test_table_listsplit.pdf'), 
showBoundary=1).build(story)
+
+    def test_small_para_inrowsplit(self):
+        '''test bug reported by Christian Zwicknagl via Yoshua Wakeham'''
+
+        data = [([Paragraph(f"({x})" + " This is a small paragraph." * 4) for 
x in range(38)],)]
+        colWidths = 200
+
+        t = Table(
+            data,
+            colWidths=colWidths,
+            splitInRow=1,
+        )
+
+        SimpleDocTemplate(outputfile("test_small_para_inrowsplit.pdf"), 
showBoundary=1).build([t])
+
 def makeSuite():
     return makeSuiteForClasses(TableTestCase)
 
-
 #noruntests
 if __name__ == "__main__":
     unittest.TextTestRunner().run(makeSuite())
-    print('saved '+outputfile('test_table_inrowsplit.pdf'))
+    print(f'saved {outputfile("test_table_inrowsplit.pdf")}')
+    print(f' and  {outputfile("test_table_listsplit.pdf")}')
     printLocation()

Reply via email to