[ZPT] CVS: Zope/lib/python/TAL - TALDefs.py:1.30 TALGenerator.py:1.57 TALInterpreter.py:1.72
Florent Guillaume
fg@nuxeo.com
Thu, 19 Sep 2002 10:39:25 -0400
Update of /cvs-repository/Zope/lib/python/TAL
In directory cvs.zope.org:/tmp/cvs-serv12623/lib/python/TAL
Modified Files:
TALDefs.py TALGenerator.py TALInterpreter.py
Log Message:
Merged Fred's latest TAL/ZPT optimizations from Zope27 into HEAD.
The merge point in Zope27 will be tagged mergepoint-to-Zope26.
=== Zope/lib/python/TAL/TALDefs.py 1.29 => 1.30 ===
--- Zope/lib/python/TAL/TALDefs.py:1.29 Wed Sep 18 11:12:48 2002
+++ Zope/lib/python/TAL/TALDefs.py Thu Sep 19 10:39:24 2002
@@ -163,8 +163,3 @@
if opcode == "version":
return version
return None
-
-import cgi
-def quote(s, escape=cgi.escape):
- return '"%s"' % escape(s, 1)
-del cgi
=== Zope/lib/python/TAL/TALGenerator.py 1.56 => 1.57 ===
--- Zope/lib/python/TAL/TALGenerator.py:1.56 Wed Sep 18 11:12:48 2002
+++ Zope/lib/python/TAL/TALGenerator.py Thu Sep 19 10:39:24 2002
@@ -162,7 +162,7 @@
if item[1] is None:
s = item[0]
else:
- s = "%s=%s" % (item[0], TALDefs.quote(item[1]))
+ s = '%s="%s"' % (item[0], cgi.escape(item[1], 1))
attrlist[i] = item[0], s
new.append(" " + s)
# if no non-optimizable attributes were found, convert to plain text
=== Zope/lib/python/TAL/TALInterpreter.py 1.71 => 1.72 ===
--- Zope/lib/python/TAL/TALInterpreter.py:1.71 Wed Sep 18 11:12:48 2002
+++ Zope/lib/python/TAL/TALInterpreter.py Thu Sep 19 10:39:24 2002
@@ -24,7 +24,7 @@
from StringIO import StringIO
from DocumentTemplate.DT_Util import ustr
-from TALDefs import quote, TAL_VERSION, TALError, METALError
+from TALDefs import TAL_VERSION, TALError, METALError
from TALDefs import isCurrentVersion, getProgramVersion, getProgramMode
from TALGenerator import TALGenerator
from TranslationContext import TranslationContext
@@ -120,7 +120,7 @@
def StringIO(self):
# Third-party products wishing to provide a full Unicode-aware
# StringIO can do so by monkey-patching this method.
- return StringIO()
+ return FasterStringIO()
def saveState(self):
return (self.position, self.col, self.stream,
@@ -185,15 +185,20 @@
bytecode_handlers = {}
- def interpret(self, program, tmpstream=None):
+ def interpretWithStream(self, program, stream):
+ oldstream = self.stream
+ self.stream = stream
+ self._stream_write = stream.write
+ try:
+ self.interpret(program)
+ finally:
+ self.stream = oldstream
+ self._stream_write = oldstream.write
+
+ def interpret(self, program):
oldlevel = self.level
self.level = oldlevel + 1
handlers = self.dispatch
- if tmpstream:
- ostream = self.stream
- owrite = self._stream_write
- self.stream = tmpstream
- self._stream_write = tmpstream.write
try:
if self.debug:
for (opcode, args) in program:
@@ -208,9 +213,6 @@
handlers[opcode](self, args)
finally:
self.level = oldlevel
- if tmpstream:
- self.stream = ostream
- self._stream_write = owrite
def do_version(self, version):
assert version == TAL_VERSION
@@ -246,8 +248,8 @@
# for start tags with no attributes; those are optimized down
# to rawtext events. Hence, there is no special "fast path"
# for that case.
- _stream_write = self._stream_write
- _stream_write("<" + name)
+ L = ["<", name]
+ append = L.append
col = self.col + _len(name) + 1
wrap = self.wrap
align = col + 1
@@ -266,13 +268,14 @@
if (wrap and
col >= align and
col + 1 + slen > wrap):
- _stream_write("\n" + " "*align)
+ append("\n" + " "*align)
col = align + slen
else:
- s = " " + s
+ append(" ")
col = col + 1 + slen
- _stream_write(s)
- _stream_write(end)
+ append(s)
+ append(end)
+ self._stream_write("".join(L))
col = col + endlen
finally:
self.col = col
@@ -307,13 +310,13 @@
if value is None:
value = name
else:
- value = "%s=%s" % (name, quote(value))
+ value = '%s="%s"' % (name, escape(value, 1))
return 1, name, value
def attrAction_tal(self, item):
- name, value, action = item[:3]
- if action in ('metal', 'tal', 'xmlns', 'i18n'):
+ if item[2] in ('metal', 'tal', 'xmlns', 'i18n'):
return self.attrAction(item)
+ name, value, action = item[:3]
ok = 1
expr, msgid = item[3:]
if self.html and name.lower() in BOOLEAN_HTML_ATTRS:
@@ -325,32 +328,28 @@
value = None
else:
ok = 0
- else:
- if expr is not None:
- evalue = self.engine.evaluateText(item[3])
- if evalue is self.Default:
- if action == 'insert': # Cancelled insert
- ok = 0
- else:
- if evalue is None:
- ok = 0
- value = evalue
- if ok:
- if msgid:
- value = self.i18n_attribute(value)
- if value is None:
- value = name
- value = "%s=%s" % (name, quote(value))
+ elif expr is not None:
+ evalue = self.engine.evaluateText(item[3])
+ if evalue is self.Default:
+ if action == 'insert': # Cancelled insert
+ ok = 0
+ else:
+ if evalue is None:
+ ok = 0
+ value = evalue
+ if msgid:
+ value = self.i18n_attribute(value)
+ if value is None:
+ value = name
+ value = '%s="%s"' % (name, escape(value, 1))
return ok, name, value
+ bytecode_handlers["<attrAction>"] = attrAction
def i18n_attribute(self, s):
# s is the value of an attribute before translation
# it may have been computed
return self.translate(s, {})
-
- bytecode_handlers["<attrAction>"] = attrAction
-
def no_tag(self, start, program):
state = self.saveState()
self.stream = stream = self.StringIO()
@@ -363,7 +362,7 @@
omit=0):
if tag_ns and not self.showtal:
return self.no_tag(start, program)
-
+
self.interpret(start)
if not isend:
self.interpret(program)
@@ -391,7 +390,8 @@
def do_rawtextBeginScope(self, (s, col, position, closeprev, dict)):
self._stream_write(s)
self.col = col
- self.do_setPosition(position)
+ self.position = position
+ self.engine.setPosition(position)
if closeprev:
engine = self.engine
engine.endScope()
@@ -403,7 +403,8 @@
def do_rawtextBeginScope_tal(self, (s, col, position, closeprev, dict)):
self._stream_write(s)
self.col = col
- self.do_setPosition(position)
+ self.position = position
+ self.engine.setPosition(position)
engine = self.engine
if closeprev:
engine.endScope()
@@ -481,7 +482,7 @@
state = self.saveState()
try:
tmpstream = self.StringIO()
- self.interpret(program, tmpstream)
+ self.interpretWithStream(program, tmpstream)
value = normalize(tmpstream.getvalue())
finally:
self.restoreState(state)
@@ -516,7 +517,7 @@
# Use a temporary stream to capture the interpretation of the
# subnodes, which should /not/ go to the output stream.
tmpstream = self.StringIO()
- self.interpret(stuff[1], tmpstream)
+ self.interpretWithStream(stuff[1], tmpstream)
# We only care about the evaluated contents if we need an implicit
# message id. All other useful information will be in the i18ndict on
# the top of the i18nStack.
@@ -724,6 +725,29 @@
bytecode_handlers_tal["onError"] = do_onError_tal
bytecode_handlers_tal["<attrAction>"] = attrAction_tal
bytecode_handlers_tal["optTag"] = do_optTag_tal
+
+
+class FasterStringIO(StringIO):
+ """Append-only version of StringIO.
+
+ This let's us have a much faster write() method.
+ """
+ def close(self):
+ if not self.closed:
+ self.write = _write_ValueError
+ StringIO.close(self)
+
+ def seek(self, pos, mode=0):
+ raise RuntimeError("FasterStringIO.seek() not allowed")
+
+ def write(self, s):
+ #assert self.pos == self.len
+ self.buflist.append(s)
+ self.len = self.pos = self.pos + len(s)
+
+
+def _write_ValueError(s):
+ raise ValueError, "I/O operation on closed file"
def test():