Commit 3a24de4f authored by Florent Guillaume's avatar Florent Guillaume

Merged Fred's latest TAL/ZPT optimizations from Zope27 into HEAD.

The merge point in Zope27 will be tagged mergepoint-to-Zope26.
parent 52193d9b
......@@ -17,7 +17,7 @@ Page Template-specific implementation of TALES, with handlers
for Python expressions, string literals, and paths.
"""
__version__='$Revision: 1.39 $'[11:-2]
__version__='$Revision: 1.40 $'[11:-2]
import re, sys
from TALES import Engine, CompilerError, _valid_name, NAME_RE, \
......@@ -46,6 +46,8 @@ def installHandlers(engine):
if sys.modules.has_key('Zope'):
import AccessControl
import AccessControl.cAccessControl
acquisition_security_filter = AccessControl.cAccessControl.aq_validate
from AccessControl import getSecurityManager
from AccessControl.ZopeGuards import guarded_getattr
try:
......@@ -65,6 +67,12 @@ else:
from zExceptions import Unauthorized
except ImportError:
Unauthorized = "Unauthorized"
def acquisition_security_filter(orig, inst, name, v, real_validate):
if real_validate(orig, inst, name, v):
return 1
raise Unauthorized, name
def call_with_ns(f, ns, arg=1):
if arg==2:
return f(None, ns)
......@@ -279,28 +287,27 @@ class DeferExpr:
return 'defer:%s' % `self._s`
def restrictedTraverse(self, path, securityManager,
def restrictedTraverse(object, path, securityManager,
get=getattr, has=hasattr, N=None, M=[],
TupleType=type(()) ):
REQUEST = {'path': path}
REQUEST['TraversalRequestNameStack'] = path = path[:] # Copy!
if not path[0]:
# If the path starts with an empty string, go to the root first.
self = self.getPhysicalRoot()
if not securityManager.validateValue(self):
object = object.getPhysicalRoot()
if not securityManager.validateValue(object):
raise Unauthorized, name
path.pop(0)
REQUEST = {'path': path}
REQUEST['TraversalRequestNameStack'] = path = path[:] # Copy!
path.reverse()
validate = securityManager.validate
object = self
__traceback_info__ = REQUEST
while path:
__traceback_info__ = REQUEST
name = path.pop()
if isinstance(name, TupleType):
object = apply(object, name)
object = object(*name)
continue
if name[0] == '_':
......@@ -363,9 +370,3 @@ def restrictedTraverse(self, path, securityManager,
object = o
return object
def validate2(orig, inst, name, v, real_validate):
if not real_validate(orig, inst, name, v):
raise Unauthorized, name
return 1
......@@ -15,17 +15,16 @@
HTML- and XML-based template objects using TAL, TALES, and METAL.
"""
__version__='$Revision: 1.28 $'[11:-2]
__version__='$Revision: 1.29 $'[11:-2]
import sys
from TAL.TALParser import TALParser
from TAL.HTMLTALParser import HTMLTALParser
from TAL.TALGenerator import TALGenerator
from TAL.TALInterpreter import TALInterpreter
from Expressions import getEngine
# Do not use cStringIO here! It's not unicode aware. :(
from StringIO import StringIO
from TAL.TALInterpreter import TALInterpreter, FasterStringIO
from Expressions import getEngine
from ExtensionClass import Base
from ComputedAttribute import ComputedAttribute
......@@ -47,7 +46,7 @@ class PageTemplate(Base):
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 macros(self):
return self.pt_macros()
......
......@@ -14,7 +14,7 @@
"""Generic Python Expression Handler
"""
__version__='$Revision: 1.9 $'[11:-2]
__version__='$Revision: 1.10 $'[11:-2]
from TALES import CompilerError
from sys import exc_info
......@@ -43,18 +43,19 @@ class PythonExpr:
if vname[0] not in '$_':
vnames.append(vname)
def _bind_used_names(self, econtext):
def _bind_used_names(self, econtext, _marker=[]):
# Bind template variables
names = {}
vars = econtext.vars
getType = econtext._engine.getTypes().get
for vname in self._f_varnames:
has, val = vars.has_get(vname)
if not has:
val = vars.get(vname, _marker)
if val is _marker:
has = val = getType(vname)
if has:
val = ExprTypeProxy(vname, val, econtext)
if has:
names[vname] = val
else:
names[vname] = val
return names
......
......@@ -15,7 +15,7 @@
An implementation of a generic TALES engine
"""
__version__='$Revision: 1.32 $'[11:-2]
__version__='$Revision: 1.33 $'[11:-2]
import re, sys, ZTUtils
from MultiMapping import MultiMapping
......@@ -44,8 +44,6 @@ class Default:
'''Retain Default'''
Default = Default()
_marker = []
class SafeMapping(MultiMapping):
'''Mapping with security declarations and limited method exposure.
......@@ -60,9 +58,6 @@ class SafeMapping(MultiMapping):
_push = MultiMapping.push
_pop = MultiMapping.pop
def has_get(self, key, _marker=[]):
v = self.get(key, _marker)
return v is not _marker, v
class Iterator(ZTUtils.Iterator):
def __init__(self, name, seq, context):
......@@ -216,8 +211,7 @@ class Context:
expression = self._engine.compile(expression)
__traceback_supplement__ = (
TALESTracebackSupplement, self, expression)
v = expression(self)
return v
return expression(self)
evaluateValue = evaluate
......@@ -257,7 +251,6 @@ class Context:
domain, msgid, mapping=mapping,
context=context, target_language=target_language)
class TALESTracebackSupplement:
"""Implementation of ITracebackSupplement"""
def __init__(self, context, expression):
......@@ -276,8 +269,6 @@ class TALESTracebackSupplement:
else:
from cgi import escape
return '<b>Names:</b><pre>%s</pre>' % (escape(s))
return None
class SimpleExpr:
......@@ -289,4 +280,3 @@ class SimpleExpr:
return self._name, self._expr
def __repr__(self):
return '<SimpleExpr %s %s>' % (self._name, `self._expr`)
......@@ -163,8 +163,3 @@ def getProgramVersion(program):
if opcode == "version":
return version
return None
import cgi
def quote(s, escape=cgi.escape):
return '"%s"' % escape(s, 1)
del cgi
......@@ -162,7 +162,7 @@ class TALGenerator:
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
......
......@@ -24,7 +24,7 @@ from cgi import escape
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
# 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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
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 @@ class TALInterpreter:
# 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.
......@@ -726,6 +727,29 @@ class TALInterpreter:
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():
from driver import FILE, parsefile
from DummyEngine import DummyEngine
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment