# HG changeset patch # User robin # Date 1571929635 -3600 # Node ID d357e2acc8568237bd60167a2ebc2737f64daa01 # Parent 80dd9e83dad9cbb341e82371f5bf9328b2f68e29 improve usage of eval/exec; version --> 3.5.32 diff -r 80dd9e83dad9 -r d357e2acc856 CHANGES.md --- a/CHANGES.md Thu Oct 24 15:53:59 2019 +0100 +++ b/CHANGES.md Thu Oct 24 16:07:15 2019 +0100 @@ -11,6 +11,13 @@ The contributors lists are in no order and apologies to those accidentally not mentioned. If we missed you, please let us know! +RELEASE 3.5.32 24/10/2019 +-------------------------- + * some chart efficiency changes + * use clock in fontFinder contributed by Matěj Cepl @ bitbucket + * improve recursive access and do some minor eval/exec fixes + * improve use of eval/exec + RELEASE 3.5.31 15/10/2019 -------------------------- * paraparser fix contributed by ravi prakash giri diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/__init__.py --- a/src/reportlab/__init__.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/__init__.py Thu Oct 24 16:07:15 2019 +0100 @@ -1,9 +1,9 @@ #Copyright ReportLab Europe Ltd. 2000-2018 #see license.txt for license details __doc__="""The Reportlab PDF generation library.""" -Version = "3.5.31" +Version = "3.5.32" __version__=Version -__date__='20191019' +__date__='20191024' import sys, os diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/graphics/barcode/test.py --- a/src/reportlab/graphics/barcode/test.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/graphics/barcode/test.py Thu Oct 24 16:07:15 2019 +0100 @@ -2,6 +2,7 @@ import os, sys, time +from reportlab import Version as __RL_Version__ from reportlab.graphics.barcode.common import * from reportlab.graphics.barcode.code39 import * from reportlab.graphics.barcode.code93 import * @@ -148,23 +149,14 @@ styleH2 = styles['Heading2'] story = [] - story.append(Paragraph('ReportLab Barcode Test Suite - full output', styleH)) - story.append(Paragraph('Generated on %s' % time.ctime(time.time()), styleN)) + story.append(Paragraph('ReportLab %s Barcode Test Suite - full output' % __RL_Version__,styleH)) + story.append(Paragraph('Generated at %s' % time.ctime(time.time()), styleN)) - story.append(Paragraph('', styleN)) - story.append(Paragraph('Repository information for this build:', styleN)) - #see if we can figure out where it was built, if we're running in source - if os.path.split(os.getcwd())[-1] == 'barcode' and os.path.isdir('.svn'): - #runnning in a filesystem svn copy - infoLines = os.popen('svn info').read() - story.append(Preformatted(infoLines, styles["Code"])) - story.append(Paragraph('About this document', styleH2)) story.append(Paragraph('History and Status', styleH2)) story.append(Paragraph(""" - This is the test suite and docoumentation for the ReportLab open source barcode API, - being re-released as part of the forthcoming ReportLab 2.0 release. + This is the test suite and docoumentation for the ReportLab open source barcode API. """, styleN)) story.append(Paragraph(""" diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/graphics/renderPDF.py --- a/src/reportlab/graphics/renderPDF.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/graphics/renderPDF.py Thu Oct 24 16:07:15 2019 +0100 @@ -349,8 +349,9 @@ drawings = [] for funcname in dir(testshapes): if funcname[0:10] == 'getDrawing': - drawing = eval('testshapes.' + funcname + '()') #execute it - docstring = eval('testshapes.' + funcname + '.__doc__') + func = getattr(testshapes,funcname) + drawing = func() #execute it + docstring = getattr(func,'__doc__','') drawings.append((drawing, docstring)) #print in a loop, with their doc strings @@ -381,32 +382,6 @@ if shout or verbose>2: print('saved %s' % ascii(fn)) -##def testFlowable(): -## """Makes a platypus document""" -## from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer -## from reportlab.lib.styles import getSampleStyleSheet -## styles = getSampleStyleSheet() -## styNormal = styles['Normal'] -## -## doc = SimpleDocTemplate('test_flowable.pdf') -## story = [] -## story.append(Paragraph("This sees is a drawing can work as a flowable", styNormal)) -## -## import testdrawings -## drawings = [] -## -## for funcname in dir(testdrawings): -## if funcname[0:10] == 'getDrawing': -## drawing = eval('testdrawings.' + funcname + '()') #execute it -## docstring = eval('testdrawings.' + funcname + '.__doc__') -## story.append(Paragraph(docstring, styNormal)) -## story.append(Spacer(18,18)) -## story.append(drawing) -## story.append(Spacer(36,36)) -## -## doc.build(story) -## print 'saves test_flowable.pdf' - if __name__=='__main__': test(shout=True) import sys diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/graphics/renderPS.py --- a/src/reportlab/graphics/renderPS.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/graphics/renderPS.py Thu Oct 24 16:07:15 2019 +0100 @@ -918,8 +918,9 @@ for funcname in dir(testshapes): if funcname[0:10] == 'getDrawing': - drawing = eval('testshapes.' + funcname + '()') #execute it - docstring = eval('testshapes.' + funcname + '.__doc__') + func = getattr(testshapes,funcname) + drawing = func() + docstring = getattr(func,'__doc__','') drawings.append((drawing, docstring)) i = 0 diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/graphics/renderSVG.py --- a/src/reportlab/graphics/renderSVG.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/graphics/renderSVG.py Thu Oct 24 16:07:15 2019 +0100 @@ -355,7 +355,7 @@ self.style['stroke-dasharray'] = ', '.join(map(str, ([array, phase]))) elif isinstance(array,(tuple,list)) and len(array) > 0: assert phase >= 0, "phase is a length in user space" - self.style['stroke-dasharray'] = ', '.join(map(str, (array+[phase]))) + self.style['stroke-dasharray'] = ', '.join(map(str, (list(array)+[phase]))) def setStrokeColor(self, color): self._strokeColor = color @@ -933,14 +933,12 @@ drawings = [] for funcname in dir(testshapes): - #if funcname[0:11] == 'getDrawing2': - # print 'hacked to only show drawing 2' if funcname[0:10] == 'getDrawing': - drawing = eval('testshapes.' + funcname + '()') - docstring = eval('testshapes.' + funcname + '.__doc__') + func = getattr(testshapes,funcname) + drawing = func() + docstring = getattr(func,'__doc__','') drawings.append((drawing, docstring)) - i = 0 for (d, docstring) in drawings: filename = os.path.join(outDir,'renderSVG_%d.svg' % i) diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/graphics/testshapes.py --- a/src/reportlab/graphics/testshapes.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/graphics/testshapes.py Thu Oct 24 16:07:15 2019 +0100 @@ -487,11 +487,14 @@ return funcNames def _evalFuncDrawing(name, D, l=None, g=None): + if g is None: g = globals() + if l is None: l = locals() + func = l.get(name,g.get(name,None)) try: - d = eval(name + '()', g or globals(), l or locals()) + d = func() except: d = getFailedDrawing(name) - D.append((d, eval(name + '.__doc__'), name[3:])) + D.append((d, getattr(func,'.__doc__',''), name[3:])) def getAllTestDrawings(doTTF=1): D = [] diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/lib/colors.py --- a/src/reportlab/lib/colors.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/lib/colors.py Thu Oct 24 16:07:15 2019 +0100 @@ -42,8 +42,9 @@ import math, re, functools from reportlab import isPy3, cmp from reportlab.lib.rl_accel import fp_str -from reportlab.lib.utils import asNative, isStr +from reportlab.lib.utils import asNative, isStr, safer_globals import collections +from ast import literal_eval class Color: """This class is used to represent color. Components red, green, blue @@ -769,8 +770,7 @@ def pcVal(self,v): v = v.strip() try: - c=eval(v[:-1]) - if not isinstance(c,(float,int)): raise ValueError + c=float(v[:-1]) c=min(100,max(0,c))/100. except: raise ValueError('bad percentage argument value %r in css color %r' % (v,self.s)) @@ -782,9 +782,8 @@ def rgbVal(self,v): v = v.strip() try: - c=eval(v[:]) - if not isinstance(c,(int,float)): raise ValueError - if isinstance(c,float) and 0<=c<=1: c *= 255 + c=float(v) + if 0' + return '<%s>' % asNative(hexlify(rawBytes(text))).upper() def unHexText(hexText): equalityCheck(hexText[0], '<', 'bad hex text') equalityCheck(hexText[-1], '>', 'bad hex text') - hexText = hexText[1:-1] - out = b'' - for i in range(int(len(hexText)/2.0)): - slice = hexText[i*2: i*2+2] - char = int2Byte(eval('0x'+slice)) - out = out + char - return out + return unhexlify(hexText[1:-1]) PadString = rawBytes(''.join(chr(int(c, 16)) for c in padding.strip().split())) @@ -735,9 +730,9 @@ try: if argv[pos+1] not in known_modes: if thisarg[0] in binaryrequired: - exec(thisarg[1] +' = int(argv[pos+1])') + exec(thisarg[1] +' = int(argv[pos+1])',vars()) else: - exec(thisarg[1] +' = argv[pos+1]') + exec(thisarg[1] +' = argv[pos+1]',vars()) if verbose: print("%s set to: '%s'." % (thisarg[3], argv[pos+1])) argv.remove(argv[pos+1]) diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/lib/rl_accel.py --- a/src/reportlab/lib/rl_accel.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/lib/rl_accel.py Thu Oct 24 16:07:15 2019 +0100 @@ -21,12 +21,14 @@ del reportlab for fn in __all__: + D={} try: - exec('from reportlab.lib._rl_accel import %s as f' % fn) - _c_funcs[fn] = f + exec('from reportlab.lib._rl_accel import %s as f' % fn,D) + _c_funcs[fn] = D['f'] if testing: _py_funcs[fn] = None except ImportError: _py_funcs[fn] = None + del D if _py_funcs: from reportlab.lib.utils import isBytes, isUnicode, isSeq, isPy3, rawBytes, asNative, asUnicode, asBytes @@ -334,19 +336,19 @@ del fn, f, G if __name__=='__main__': - import sys, os + import sys, os, subprocess for modname in 'reportlab.lib.rl_accel','reportlab.lib._rl_accel': for cmd in ( #"unicode2T1('abcde fghi . jkl ; mno',fonts)", #"unicode2T1(u'abcde fghi . jkl ; mno',fonts)", - "_instanceStringWidthU(font,'abcde fghi . jkl ; mno',10)", - "_instanceStringWidthU(font,u'abcde fghi . jkl ; mno',10)", + "instanceStringWidthT1(font,'abcde fghi . jkl ; mno',10)", + "instanceStringWidthT1(font,u'abcde fghi . jkl ; mno',10)", ): print('%s %s' % (modname,cmd)) s=';'.join(( "from reportlab.pdfbase.pdfmetrics import getFont", - "from %s import unicode2T1,_instanceStringWidthU" % modname, + "from %s import unicode2T1,instanceStringWidthT1" % modname, "fonts=[getFont('Helvetica')]+getFont('Helvetica').substitutionFonts""", "font=fonts[0]", )) - os.system('%s -m timeit -s"%s" "%s"' % (sys.executable,s,cmd)) + subprocess.check_call([sys.executable,'-mtimeit','-s',s,cmd]) diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/pdfbase/_cidfontdata.py --- a/src/reportlab/pdfbase/_cidfontdata.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/pdfbase/_cidfontdata.py Thu Oct 24 16:07:15 2019 +0100 @@ -480,4 +480,4 @@ ## out.append(word) ## else: ## out.append(word + ',') -## return eval(''.join(out)) +## return eval(''.join(out),{}) diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/platypus/doctemplate.py --- a/src/reportlab/platypus/doctemplate.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/platypus/doctemplate.py Thu Oct 24 16:07:15 2019 +0100 @@ -1215,7 +1215,7 @@ try: if lifetime not in self._allowedLifetimes: raise ValueError('bad lifetime %r not in %r'%(lifetime,self._allowedLifetimes)) - exec(stmt, {},NS) + exec(stmt, NS) except: for k in NS.keys(): if k not in K0: diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/platypus/flowables.py --- a/src/reportlab/platypus/flowables.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/platypus/flowables.py Thu Oct 24 16:07:15 2019 +0100 @@ -30,7 +30,7 @@ from reportlab.lib.rl_accel import fp_str from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY from reportlab.lib.styles import _baseFontName -from reportlab.lib.utils import strTypes +from reportlab.lib.utils import strTypes, safer_globals from reportlab.lib.abag import ABag from reportlab.pdfbase import pdfutils from reportlab.pdfbase.pdfmetrics import stringWidth @@ -755,7 +755,7 @@ def wrap(self, availWidth, availHeight): return (0,0) def draw(self): - exec(self.command, globals(), {'canvas':self.canv}) + exec(self.command, safer_globals(), {'canvas':self.canv}) def _nullCallable(*args,**kwds): pass diff -r 80dd9e83dad9 -r d357e2acc856 src/reportlab/platypus/tableofcontents.py --- a/src/reportlab/platypus/tableofcontents.py Thu Oct 24 15:53:59 2019 +0100 +++ b/src/reportlab/platypus/tableofcontents.py Thu Oct 24 16:07:15 2019 +0100 @@ -2,7 +2,7 @@ #see license.txt for license details #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/platypus/tableofcontents.py -__version__='3.3.0' +__version__='3.5.32' __doc__="""Experimental class to generate Tables of Contents easily This module defines a single TableOfContents() class that can be used to @@ -48,6 +48,7 @@ from reportlab.lib.units import cm from reportlab.lib.utils import commasplit, escapeOnce, encode_label, decode_label, strTypes, asUnicode, asNative from reportlab.lib.styles import ParagraphStyle, _baseFontName +from reportlab.lib import sequencer as rl_sequencer from reportlab.platypus.paragraph import Paragraph from reportlab.platypus.doctemplate import IndexingFlowable from reportlab.platypus.tables import TableStyle, Table @@ -55,6 +56,7 @@ from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.pdfgen import canvas import unicodedata +from ast import literal_eval def unquote(txt): from xml.sax.saxutils import unescape @@ -239,7 +241,7 @@ def drawTOCEntryEnd(canvas, kind, label): '''Callback to draw dots and page numbers after each entry.''' label = label.split(',') - page, level, key = int(label[0]), int(label[1]), eval(label[2],{}) + page, level, key = int(label[0]), int(label[1]), literal_eval(label[2]) style = self.getLevelStyle(level) if self.dotsMinLevel >= 0 and level >= self.dotsMinLevel: dot = ' . ' @@ -305,13 +307,11 @@ self._flowable = None self.setup(**kwargs) - def getFormatFunc(self,format): + def getFormatFunc(self,formatName): try: - D = {} - exec('from reportlab.lib.sequencer import _format_%s as formatFunc' % format, D) - return D['formatFunc'] + return getattr(rl_sequencer,'_format_%s' % formatName) except ImportError: - raise ValueError('Unknown format %r' % format) + raise ValueError('Unknown sequencer format %r' % formatName) def setup(self, style=None, dot=None, tableStyle=None, headers=True, name=None, format='123', offset=0): """