[ZPT] CVS: Zope27/lib/python/TAL - TALInterpreter.py:1.68.26.3
Fred L. Drake, Jr.
fdrake@acm.org
Tue, 17 Sep 2002 12:30:48 -0400
Update of /cvs-repository/Zope27/lib/python/TAL
In directory cvs.zope.org:/tmp/cvs-serv20248
Modified Files:
Tag: Zope-2_7-development-branch
TALInterpreter.py
Log Message:
FasterStringIO: Faster, append-only subclass of the StringIO, since
we were spending a lot of time in the write() method.
interpret(): Remove the tmpstream argument.
interpretWithStream(): New method; equivalent to interpret(prog, stream).
Some additional minor optimizations.
=== Zope27/lib/python/TAL/TALInterpreter.py 1.68.26.2 => 1.68.26.3 ===
--- Zope27/lib/python/TAL/TALInterpreter.py:1.68.26.2 Sun Sep 8 22:04:52 2002
+++ Zope27/lib/python/TAL/TALInterpreter.py Tue Sep 17 12:30:47 2002
@@ -18,7 +18,7 @@
import sys
import getopt
import re
-from types import ListType
+from types import ListType, StringTypes
from cgi import escape
# Do not use cStringIO here! It's not unicode aware. :(
from StringIO import StringIO
@@ -119,7 +119,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,
@@ -184,15 +184,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:
@@ -207,9 +212,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
@@ -245,8 +247,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
@@ -265,13 +267,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
@@ -362,7 +365,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)
@@ -390,7 +393,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()
@@ -402,7 +406,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()
@@ -480,7 +485,7 @@
state = self.saveState()
try:
tmpstream = self.StringIO()
- self.interpret(program, tmpstream)
+ self.interpretWithStream(program, tmpstream)
value = normalize(tmpstream.getvalue())
finally:
self.restoreState(state)
@@ -515,7 +520,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.
@@ -723,6 +728,30 @@
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
+ newpos = self.pos + len(s)
+ self.buflist.append(s)
+ self.len = self.pos = newpos
+
+
+def _write_ValueError(s):
+ raise ValueError, "I/O operation on closed file"
def test():