make paraparser syntax errors real and fix <sup/sub> tags to have relative values; version-->3.3.1
authorrobin
Tue, 01 Mar 2016 13:35:52 +0000
changeset 4255 89ea1d46b4a0
parent 4254 b0f678afac12
child 4256 d09010e5b1cc
make paraparser syntax errors real and fix <sup/sub> tags to have relative values; version-->3.3.1
src/reportlab/__init__.py
src/reportlab/platypus/paraparser.py
tests/test_platypus_paragraphs.py
--- a/src/reportlab/__init__.py	Tue Mar 01 10:05:59 2016 +0000
+++ b/src/reportlab/__init__.py	Tue Mar 01 13:35:52 2016 +0000
@@ -1,9 +1,9 @@
 #Copyright ReportLab Europe Ltd. 2000-2016
 #see license.txt for license details
 __doc__="""The Reportlab PDF generation library."""
-Version = "3.3.0"
+Version = "3.3.1"
 __version__=Version
-__date__='20160217'
+__date__='20160301'
 
 import sys, os, imp
 
--- a/src/reportlab/platypus/paraparser.py	Tue Mar 01 10:05:59 2016 +0000
+++ b/src/reportlab/platypus/paraparser.py	Tue Mar 01 13:35:52 2016 +0000
@@ -99,6 +99,27 @@
         normalizer = normalizer or getattr(self,'_normalizer')
         return normalizer*self._value
 
+def fontSizeNormalize(frag,attr,default):
+    if not hasattr(frag,attr): return default
+    v = _numpct(getattr(frag,attr),allowRelative=True)
+    return (v[1]+frag.fontSize) if isinstance(v,tuple) else v.normalizedValue(frag.fontSize) if isinstance(v,_PCT) else v
+
+class _CheckSup:
+    '''class for syntax checking <sup> attributes
+    if the check succeeds then we always return the string for later evaluation
+    '''
+    def __init__(self,kind):
+        self.kind = kind
+        self.fontSize = 10
+
+    def __call__(self,s):
+        setattr(self,self.kind,s)
+        try:
+            fontSizeNormalize(self,self.kind,None)
+            return s
+        except:
+            raise ValueError('<sup> invalid value %r for attribute %s' % (s,self.kind))
+
 def _valignpc(s):
     s = s.lower()
     if s in ('baseline','sub','super','top','text-top','middle','bottom','text-bottom'):
@@ -251,8 +272,8 @@
                 'format': ('format',None),
                 }
 _supAttrMap = {
-                'rise': ('supr', _num),
-                'size': ('sups', _num),
+                'rise': ('supr', _CheckSup('rise')),
+                'size': ('sups', _CheckSup('size')),
                 }
 
 def _addAttributeNames(m):
@@ -791,6 +812,8 @@
 
     def _syntax_error(self,message):
         if message[:10]=="attribute " and message[-17:]==" value not quoted": return
+        if self._crashOnError:
+            raise ValueError('paraparser: syntax error: %s' % message)
         self.errors.append(message)
 
     def start_greek(self, attr):
@@ -1064,18 +1087,14 @@
             if k in attrMap:
                 j = attrMap[k]
                 func = j[1]
-                try:
-                    A[j[0]] = v if func is None else func(v)
-                except:
-                    self._syntax_error('%s: invalid value %s'%(k,v))
+                A[j[0]] = v if func is None else func(v)
             else:
-                raise ValueError('invalid attribute name %s attrMap=%r'% (k,list(sorted(attrMap.keys()))))
-                self._syntax_error('invalid attribute name %s'%k)
+                self._syntax_error('invalid attribute name %s attrMap=%r'% (k,list(sorted(attrMap.keys()))))
         return A
 
     #----------------------------------------------------------------
 
-    def __init__(self,verbose=0, caseSensitive=0, ignoreUnknownTags=1):
+    def __init__(self,verbose=0, caseSensitive=0, ignoreUnknownTags=1, crashOnError=True):
         HTMLParser.__init__(self,
             **(dict(convert_charrefs=False) if sys.version_info>=(3,4) else {}))
         self.verbose = verbose
@@ -1083,6 +1102,7 @@
         #all start/end_ methods should have a lower case version for HMTMParser
         self.caseSensitive = caseSensitive
         self.ignoreUnknownTags = ignoreUnknownTags
+        self._crashOnError = crashOnError
 
     def _iReset(self):
         self.fragList = []
@@ -1121,11 +1141,11 @@
                 frag.sup = 0
 
             if frag.sub:
-                frag.rise = -getattr(frag,'supr',frag.fontSize*subFraction)
-                frag.fontSize = getattr(frag,'sups',frag.fontSize-min(sizeDelta,0.2*frag.fontSize))
+                frag.rise = -fontSizeNormalize(frag,'supr',frag.fontSize*subFraction)
+                frag.fontSize = fontSizeNormalize(frag,'sups',frag.fontSize-min(sizeDelta,0.2*frag.fontSize))
             elif frag.sup:
-                frag.rise = getattr(frag,'supr',frag.fontSize*supFraction)
-                frag.fontSize = getattr(frag,'sups',frag.fontSize-min(sizeDelta,0.2*frag.fontSize))
+                frag.rise = fontSizeNormalize(frag,'supr',frag.fontSize*supFraction)
+                frag.fontSize = fontSizeNormalize(frag,'sups',frag.fontSize-min(sizeDelta,0.2*frag.fontSize))
 
             if frag.greek:
                 frag.fontName = 'symbol'
--- a/tests/test_platypus_paragraphs.py	Tue Mar 01 10:05:59 2016 +0000
+++ b/tests/test_platypus_paragraphs.py	Tue Mar 01 13:35:52 2016 +0000
@@ -553,6 +553,9 @@
         a(XPreformatted("This is a <sup rise=8 size=7><span color='red'>sup</span></sup>rise=8 size=7.",p_style))
         a(Paragraph("This is a <sup rise=9 size=7><span color='red'>sup</span></sup>rise=9 size=7.",p_style))
         a(XPreformatted("This is a <sup rise=9 size=7><span color='red'>sup</span></sup>rise=9 size=7.",p_style))
+        a(Paragraph("This is a <sup rise=90% size=70%><span color='red'>sup</span></sup>rise=90% size=70%.",p_style))
+        a(Paragraph("This is a <sup rise=-2 size=-2><span color='red'>sup</span></sup>rise=-2 size=-2.",p_style))
+        a(Paragraph("This is a <sup rise=-4 size=-3><span color='red'>sup</span></sup>rise=-4 size=-3.",p_style))
         a(PageBreak())
 
         a(Paragraph('<br/><b>Some Paragraph tests of &lt;img width="x%" height="x%"</b>...', normal))