[ZPT] CVS: Packages/TAL - HTMLTALParser.py:1.23 TALDefs.py:1.13 TALGenerator.py:1.24 TALInterpreter.py:1.24
guido@digicool.com
guido@digicool.com
Fri, 23 Mar 2001 16:35:49 -0500 (EST)
Update of /cvs-repository/Packages/TAL
In directory korak:/tmp/cvs-serv4958
Modified Files:
HTMLTALParser.py TALDefs.py TALGenerator.py TALInterpreter.py
Log Message:
- Support on-error. The engine must raise TALDefs.TALESError() to
trigger it (other errors are not caught). TALESError() takes up to
three args: msg, position, info, where msg is the message string,
position is a (lineno, offset) tuple, and info is the exception info
tuple (type, value, traceback) from sys.exc_info(). Both default to
tuples with all None values. You can choose to subclass this
exception of course.
- Require explicit </endtag> for <starttags> that have TAL or METAL
attributes. (Note that this detected a bug in the first example on
http://dev.zope.org/Wikis/DevSite/Projects/ZPT/RenderErrorHandlingStrategies;
the <span> wasn't closed.
--- Updated File HTMLTALParser.py in package Packages/TAL --
--- HTMLTALParser.py 2001/03/22 17:35:43 1.22
+++ HTMLTALParser.py 2001/03/23 21:35:49 1.23
@@ -204,10 +204,10 @@
self.close_para_tags(tag)
self.scan_xmlns(attrs)
attrlist, taldict, metaldict = self.extract_attrs(attrs)
- if taldict.get("replace") or taldict.get("content"):
+ if taldict.get("content"):
self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
self.getpos())
- self.gen.emitEndElement(tag)
+ self.gen.emitEndElement(tag, implied=-1)
else:
self.gen.emitStartElement(tag, attrlist, taldict, metaldict,
self.getpos(), isend=1)
@@ -261,11 +261,11 @@
# Pick out trailing whitespace from the program, and
# insert the close tag before the whitespace.
white = self.gen.unEmitWhitespace()
- self.gen.emitEndElement(tag)
+ self.gen.emitEndElement(tag, implied=implied)
if white:
self.gen.emitRawText(white)
else:
- self.gen.emitEndElement(tag)
+ self.gen.emitEndElement(tag, implied=implied)
self.tagstack.pop()
self.pop_xmlns()
--- Updated File TALDefs.py in package Packages/TAL --
--- TALDefs.py 2001/03/17 03:49:29 1.12
+++ TALDefs.py 2001/03/23 21:35:49 1.13
@@ -108,9 +108,11 @@
"replace",
"repeat",
"attributes",
+ "on-error",
]
class TALError(Exception):
+
def __init__(self, msg, position=(None, None)):
assert msg != ""
self.msg = msg
@@ -128,6 +130,24 @@
class METALError(TALError):
pass
+class TALESError(TALError):
+
+ # This exception can carry around another exception + traceback
+
+ def __init__(self, msg, position=(None, None), info=(None, None, None)):
+ t, v, tb = info
+ if t:
+ if issubclass(t, Exception) and t.__module__ == "exceptions":
+ err = t.__name__
+ else:
+ err = str(t)
+ v = v is not None and str(v)
+ if v:
+ err = "%s: %s" % (err, v)
+ msg = "%s: %s" % (msg, err)
+ TALError.__init__(self, msg, position)
+ self.info = info
+
import re
_attr_re = re.compile(r"\s*([^\s]+)\s*(.*)\Z", re.S)
_subst_re = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S)
@@ -147,11 +167,11 @@
dict[name] = expr
return dict
-def parseSubstitution(arg):
+def parseSubstitution(arg, position=(None, None)):
m = _subst_re.match(arg)
if not m:
- print "Bad syntax in replace/content:", `arg`
- return None, None
+ raise TALError("Bad syntax in substitution text: " + `onError`,
+ position)
key, expr = m.group(1, 2)
if not key:
key = "text"
--- Updated File TALGenerator.py in package Packages/TAL --
--- TALGenerator.py 2001/03/22 19:45:54 1.23
+++ TALGenerator.py 2001/03/23 21:35:49 1.24
@@ -221,6 +221,19 @@
else:
self.emit("setGlobal", name, cexpr)
+ def emitOnError(self, name, onError, position):
+ block = self.popProgram()
+ key, expr = parseSubstitution(onError, position)
+ cexpr = self.compileExpression(expr)
+ if key == "text":
+ self.emit("insertText", cexpr, [])
+ else:
+ assert key == "structure"
+ self.emit("insertStructure", cexpr, attrDict, [])
+ self.emitEndTag(name)
+ handler = self.popProgram()
+ self.emit("onError", block, handler)
+
def emitCondition(self, expr):
cexpr = self.compileExpression(expr)
program = self.popProgram()
@@ -236,9 +249,7 @@
self.emit("loop", name, cexpr, program)
def emitSubstitution(self, arg, attrDict={}, position=(None, None)):
- key, expr = parseSubstitution(arg)
- if not key:
- raise TALError("Bad syntax in content/replace: " + `arg`, position)
+ key, expr = parseSubstitution(arg, position)
cexpr = self.compileExpression(expr)
program = self.popProgram()
if key == "text":
@@ -346,12 +357,13 @@
useMacro = metaldict.get("use-macro")
defineSlot = metaldict.get("define-slot")
fillSlot = metaldict.get("fill-slot")
- defines = taldict.get("define")
+ define = taldict.get("define")
condition = taldict.get("condition")
content = taldict.get("content")
replace = taldict.get("replace")
repeat = taldict.get("repeat")
attrsubst = taldict.get("attributes")
+ onError = taldict.get("on-error")
if len(metaldict) > 1:
raise METALError("at most one METAL attribute per element",
position)
@@ -383,10 +395,16 @@
if fillSlot:
self.pushProgram()
todo["fillSlot"] = fillSlot
- if defines:
+ if define:
self.emit("beginScope")
- self.emitDefines(defines, position)
- todo["define"] = defines
+ if onError:
+ self.pushProgram() # handler
+ self.emitStartTag(name, attrlist)
+ self.pushProgram() # block
+ todo["onError"] = onError
+ if define:
+ self.emitDefines(define, position)
+ todo["define"] = define
if condition:
self.pushProgram()
todo["condition"] = condition
@@ -417,7 +435,7 @@
if isend:
self.emitEndElement(name, isend)
- def emitEndElement(self, name, isend=0):
+ def emitEndElement(self, name, isend=0, implied=0):
todo = self.todoPop()
if not todo:
# Shortcut
@@ -434,9 +452,20 @@
repeat = todo.get("repeat")
replace = todo.get("replace")
condition = todo.get("condition")
+ onError = todo.get("onError")
define = todo.get("define")
repldict = todo.get("repldict", {})
+ if implied > 0:
+ if defineMacro or useMacro or defineSlot or fillSlot:
+ exc = METALError
+ what = "METAL"
+ else:
+ exc = TALError
+ what = "TAL"
+ raise exc("%s attributes on <%s> require explicit </%s>" %
+ (what, name, name), position)
+
if content:
self.emitSubstitution(content, {}, position)
if not isend:
@@ -448,6 +477,8 @@
self.emitSubstitution(replace, repldict, position)
if condition:
self.emitCondition(condition)
+ if onError:
+ self.emitOnError(name, onError, position)
if define:
self.emit("endScope")
if defineMacro:
--- Updated File TALInterpreter.py in package Packages/TAL --
--- TALInterpreter.py 2001/03/22 19:45:54 1.23
+++ TALInterpreter.py 2001/03/23 21:35:49 1.24
@@ -91,8 +91,13 @@
import getopt
import cgi
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
+
from XMLParser import XMLParser
-from TALDefs import TALError, quote
+from TALDefs import TALError, TALESError, quote
BOOLEAN_HTML_ATTRS = [
# List of Boolean attributes in HTML that should be rendered in
@@ -129,7 +134,18 @@
self.slots = {}
self.currentMacro = None
self.position = None, None # (lineno, offset)
+ self.col = 0
+ self.level = 0
+
+ def saveState(self):
+ return (self.position, self.col, self.stream)
+
+ def restoreState(self, state):
+ (self.position, self.col, self.stream) = state
+ def restoreOutputState(self, state):
+ (dummy, self.col, self.stream) = state
+
def __call__(self):
if self.html:
self.endsep = " />"
@@ -139,8 +155,6 @@
if self.col > 0:
self.stream_write("\n")
- col = 0
-
def stream_write(self, s):
self.stream.write(s)
i = string.rfind(s, '\n')
@@ -149,8 +163,6 @@
else:
self.col = len(s) - (i + 1)
- level = 0
-
def interpret(self, program):
self.level = self.level + 1
for item in program:
@@ -297,6 +309,21 @@
self.interpret(compiledSlot)
else:
self.interpret(block)
+
+ def do_onError(self, block, handler):
+ if not self.tal:
+ self.interpret(block)
+ return
+ state = self.saveState()
+ self.stream = stream = StringIO()
+ try:
+ self.interpret(block)
+ except TALESError, err:
+ self.restoreState(state)
+ self.interpret(handler)
+ else:
+ self.restoreOutputState(state)
+ self.stream_write(stream.getvalue())
def test():
from driver import FILE, parsefile