reportlab/platypus/doctemplate.py
changeset 2955 cc16265295fb
parent 2950 6c243412b06c
child 2956 5c17941635bd
--- a/reportlab/platypus/doctemplate.py	Thu Aug 21 13:15:24 2008 +0000
+++ b/reportlab/platypus/doctemplate.py	Thu Aug 21 16:50:11 2008 +0000
@@ -35,6 +35,7 @@
 from reportlab.rl_config import defaultPageSize, verbose
 import reportlab.lib.sequencer
 from reportlab.pdfgen import canvas
+import tokenize
 
 from types import *
 import sys
@@ -338,6 +339,8 @@
     def __init__(self, filename, **kw):
         """create a document template bound to a filename (see class documentation for keyword arguments)"""
         self.filename = filename
+        self._nameSpace = dict(doc=self)
+        self._lifetimes = {}
 
         for k in self._initArgs.keys():
             if not kw.has_key(k):
@@ -434,6 +437,7 @@
             check the next page template
             hang a page begin
         '''
+        self._removeVars('page')
         #detect infinite loops...
         if self._curPageFlowableCount == 0:
             self._emptyPages += 1
@@ -488,6 +492,7 @@
         ''' Handles the semantics of the end of a frame. This includes the selection of
             the next frame or if this is the last frame then invoke pageEnd.
         '''
+        self._removeVars('frame')
         self._leftExtraIndent = self.frame._leftExtraIndent
         self._rightExtraIndent = self.frame._rightExtraIndent
 
@@ -557,7 +562,6 @@
 
     def handle_currentFrame(self,fx,resume=0):
         '''change to the frame with name or index fx'''
-
         self.handle_nextFrame(fx,resume)
         self.handle_frameEnd(resume)
 
@@ -694,7 +698,7 @@
 
         #each distinct pass gets a sequencer
         self.seq = reportlab.lib.sequencer.Sequencer()
-        
+
         self.canv = canvasmaker(filename or self.filename,
                                 pagesize=self.pagesize,
                                 invariant=self.invariant,
@@ -710,6 +714,7 @@
         self.handle_documentBegin()
 
     def _endBuild(self):
+        self._removeVars('build')
         if self._hanging!=[] and self._hanging[-1] is PageBegin:
             del self._hanging[-1]
             self.clean_hanging()
@@ -885,6 +890,64 @@
         '''called after a flowable has been rendered'''
         pass
 
+    _allowedLifetimes = 'page','frame','build','forever'
+    def docAssign(self,var,expr,lifetime):
+        var=var.strip()+'\n'
+        expr=expr.strip()
+        T=tokenize.generate_tokens(lambda :var)
+        tokens=[]
+        while 1:
+            t=T.next()
+            if t[0]==tokenize.NEWLINE: break
+            tokens.append(t)
+        simple = len(tokens)==1
+        del T
+        var=var.strip()
+        try:
+            if lifetime not in self._allowedLifetimes:
+                raise ValueError('bad lifetime %r not in %r'%(lifetime,self._allowedLifetimes))
+            exec '%s=(%s)' % (var,expr) in {},self._nameSpace
+        except:
+            exc = sys.exc_info()[1]
+            args = list(exc.args)
+            args[-1] += '\ndocAssign %s=(%s) lifetime=%r failed!' % (var,expr,lifetime)
+            exc.args = tuple(args)
+            raise
+        if simple:
+            for v in self._lifetimes.itervalues():
+                if var in v:
+                    v.remove(var)
+            self._lifetimes.setdefault(lifetime,set([])).add(var)
+
+    def docExec(self,stmt):
+        stmt=stmt.strip()
+        try:
+            exec stmt in {},self._nameSpace
+        except:
+            exc = sys.exc_info()[1]
+            args = list(exc.args)
+            args[-1] += '\ndocExec %s failed!' % stmt
+            exc.args = tuple(args)
+            raise
+
+    def _removeVars(self,lifetime):
+        for k in self._lifetimes.setdefault(lifetime,[]):
+            try:
+                del self._nameSpace[k]
+            except KeyError:
+                pass
+        del self._lifetimes[lifetime]
+
+    def docEval(self,expr):
+        try:
+            return eval(expr.strip(),{},self._nameSpace)
+        except:
+            exc = sys.exc_info()[1]
+            args = list(exc.args)
+            args[-1] += '\ndocEval %s failed!' % expr
+            exc.args = tuple(args)
+            raise
+
 class SimpleDocTemplate(BaseDocTemplate):
     """A special case document template that will handle many simple documents.
        See documentation for BaseDocTemplate.  No pageTemplates are required