[ZPT] CVS: Packages/Products/PageTemplates (Products/DC/PageTemplates) - HISTORY.txt:1.1.2.1 CHANGES.txt:1.6.2.2 Expressions.py:1.13.2.2 PageTemplate.py:1.11.2.1 PageTemplateFile.py:1.1.2.2 PythonExpr.py:1.2.2.2 README.txt:1.1.6.1 TALES.py:1.13.2.1 ZPythonExpr.py:1.2.2.2 ZRPythonExpr.py:1.2.2.2 ZopePageTemplate.py:1.9.2.2 version.txt:1.6.2.2
evan@serenade.digicool.com
evan@serenade.digicool.com
Sat, 16 Jun 2001 11:55:59 -0400
Update of /cvs-repository/Packages/Products/PageTemplates
In directory serenade:/home/evan/Zope/pt/lib/python/Products/PageTemplates
Modified Files:
Tag: zpt-1_3_0
CHANGES.txt Expressions.py PageTemplate.py PageTemplateFile.py
PythonExpr.py README.txt TALES.py ZPythonExpr.py
ZRPythonExpr.py ZopePageTemplate.py version.txt
Added Files:
Tag: zpt-1_3_0
HISTORY.txt
Log Message:
Merge trunk changes for release 1.3.2
--- Added File HISTORY.txt in package Packages/Products/PageTemplates ---
Page Template history
This file contains change information for previous versions of
PageTemplates. Change information for the current release can be found
in the file CHANGES.txt.
Version 1.3.1
Features Added
- Added error logging to PageTemplateFiles.
- Refactored PythonExpr, and added support for Zope 2.4
Version 1.3.0
Features Added
- New builtin variables 'default', 'user', and 'attrs'.
- Removed path modifiers.
- Added '|' operator for paths.
- Tweaked parameters passed when calling DTML.
- Expression types now have corresponding builtin functions in
Python expressions.
Version 1.2.1
Bug Fixed
- 'repeat' variable access was broken.
Version 1.2.0
Features Added
- Depends on the new ZTUtils package, which adds batching and
tree widget capabilities.
- Path expressions now have optional path modifiers. These
appear in parenthesis before the path, and include 'if',
'exists', and 'nocall'.
- Changed nocall: and exists: expressions types into path modifiers.
- The 'if' path modifier can cancel any TAL action.
Version 1.1.0
Features Added
- Changed tests to match TAL's omitted attributes.
Version 1.0.0
- Various minor bugs fixed
Version 1.0.0b1
- All functionality described in the Project Wiki is implemented
--- Updated File CHANGES.txt in package Packages/Products/PageTemplates --
--- CHANGES.txt 2001/05/25 14:37:21 1.6.2.1
+++ CHANGES.txt 2001/06/16 15:55:28 1.6.2.2
@@ -1,51 +1,18 @@
-2001-05-25 Evan Simpson <evan@digicool.com>
+Page Template changes
- * Version 1.3.1
- * Added error logging to PageTemplateFiles.
- * Refactored PythonExpr, and added support for Zope 2.4
+ This file contains change information for the current release.
+ Change information for previous versions can be found in the
+ file HISTORY.txt.
-2001-05-21 Evan Simpson <evan@digicool.com>
+ Version 1.3.2
- * Version 1.3.0
- * Guido fixed use of nested macros.
- * New builtin variables 'default', 'user', and 'attrs'.
- * Removed path modifiers.
- * Added '|' operator for paths.
- * Tweaked parameters passed when calling DTML.
- * Expression types now have corresponding builtin functions in
- Python expressions.
+ Features Added
-2001-05-07 Evan Simpson <evan@digicool.com>
+ - Adopted Zope-style CHANGES.txt and HISTORY.txt
+ - Improved execution performance
+ - nocall: paths are back in.
- * Version 1.2.1
- * Bugfixes for 'repeat' variable access
+ Bugs Fixed
-2001-04-27 Evan Simpson <evan@digicool.com>
-
- * Version 1.2.0
- * Depends on the new ZTUtils package, which adds batching and
- tree widget capabilities.
- * Path expressions now have optional path modifiers. These
- appear in parenthesis before the path, and include 'if',
- 'exists', and 'nocall'.
- * Changed nocall: and exists: expressions types into path modifiers.
- * tal:attributes no longer inserts empty attributes into
- source.
- * The 'if' path modifier can cancel any TAL action.
-
-2001-04-10 Evan Simpson <evan@digicool.com>
-
- * Version 1.1.0
- * Bug fixes
- * Tell TAL not to parse replacement structural text
- * Change tests to match TAL's omitted attributes
-
-2001-03-30 Evan Simpson <evan@digicool.com>
-
- * Version 1.0.0
- * Minor bugs fixed
-
-2001-03-27 Evan Simpson <evan@digicool.com>
-
- * Version 1.0.0b1
- * All functionality described in the Project Wiki is implemented
+ - TALES expressions let any string exception through, not just
+ Redirect and Unauthorized.
--- Updated File Expressions.py in package Packages/Products/PageTemplates --
--- Expressions.py 2001/05/25 14:37:21 1.13.2.1
+++ Expressions.py 2001/06/16 15:55:28 1.13.2.2
@@ -108,7 +108,7 @@
def installHandlers(engine):
reg = engine.registerType
pe = PathExpr
- for pt in ('standard', 'path', 'exists'):
+ for pt in ('standard', 'path', 'exists', 'nocall'):
reg(pt, pe)
reg('string', StringExpr)
reg('python', PythonExpr)
@@ -171,45 +171,46 @@
dp.reverse()
return base, path, dp
- def _eval(self, (base, path, dp), econtext):
- path = list(path) # Copy!
- contexts = econtext.contexts
- var = contexts['var']
- # Expand dynamic path parts from right to left.
- for i, varname in dp:
- val = var[varname]
- if type(val) is type(''):
- path[i] = val
- else:
- # If the value isn't a string, assume it's a sequence
- # of path names.
- path[i:i+1] = list(val)
- try:
- __traceback_info__ = base
- if base == 'CONTEXTS':
- ob = contexts
- else:
- has, ob = var.has_get(base)
- if not has:
- ob = contexts[base]
- return restrictedTraverse(ob, path)
- except (AttributeError, KeyError, TypeError, IndexError,
- 'Unauthorized'), e:
- return Undefined(self._s, sys.exc_info())
-
- def __call__(self, econtext):
- for pathinfo in self._paths:
- ob = self._eval(pathinfo, econtext)
- exists = not isinstance(ob, Undefined)
-
- if exists:
- # We're done
+ def _eval(self, econtext, securityManager,
+ list=list, isinstance=isinstance, StringType=type(''),
+ render=render):
+ vars = econtext.vars
+ exists = 0
+ for base, path, dp in self._paths:
+ path = list(path) # Copy!
+ # Expand dynamic path parts from right to left.
+ for i, varname in dp:
+ val = vars[varname]
+ if isinstance(val, StringType):
+ path[i] = val
+ else:
+ # If the value isn't a string, assume it's a sequence
+ # of path names.
+ path[i:i+1] = list(val)
+ try:
+ __traceback_info__ = base
+ if base == 'CONTEXTS':
+ ob = econtext.contexts
+ else:
+ ob = vars[base]
+ if path:
+ ob = restrictedTraverse(ob, path, securityManager)
+ exists = 1
break
+ except (AttributeError, KeyError, TypeError, IndexError,
+ 'Unauthorized'), e:
+ ob = Undefined(self._s, sys.exc_info())
+
if self._name == 'exists':
# All we wanted to know is whether one of the paths exist.
return exists
+ if self._name == 'nocall' or isinstance(ob, StringType):
+ return ob
# Return the rendered object
- return render(ob, econtext.contexts)
+ return render(ob, vars)
+
+ def __call__(self, econtext):
+ return self._eval(econtext, getSecurityManager())
def __str__(self):
return '%s expression "%s"' % (self._name, self._s)
@@ -249,7 +250,10 @@
def __call__(self, econtext):
vvals = []
for var in self._vars:
- vvals.append(var(econtext))
+ v = var(econtext)
+ if isinstance(v, Exception):
+ raise v
+ vvals.append(v)
return self._expr % tuple(vvals)
def __str__(self):
@@ -270,26 +274,20 @@
return '<NotExpr %s>' % `self._s`
-def restrictedTraverse(self, path):
+def restrictedTraverse(self, path, securityManager,
+ get=getattr, has=hasattr, N=None, M=[]):
- if not path: return self
-
- get=getattr
- N=None
- M=[] #marker
-
- REQUEST={'TraversalRequestNameStack': path}
- securityManager = getSecurityManager()
-
- plen = len(path)
i = 0
if not path[0]:
# If the path starts with an empty string, go to the root first.
- i = 1
self = self.getPhysicalRoot()
if not securityManager.validateValue(self):
raise 'Unauthorized', name
-
+ i = 1
+
+ plen = len(path)
+ REQUEST={'TraversalRequestNameStack': path}
+ validate = securityManager.validate
object = self
while i < plen:
__traceback_info__ = (path, i)
@@ -301,9 +299,9 @@
raise AttributeError, name
if name=='..':
- o = getattr(object, 'aq_parent', M)
+ o = get(object, 'aq_parent', M)
if o is not M:
- if not securityManager.validate(object, object, name, o):
+ if not validate(object, object, name, o):
raise 'Unauthorized', name
object=o
continue
@@ -313,27 +311,27 @@
o=t(REQUEST, name)
container = None
- if (hasattr(get(object, 'aq_base', object), name)
+ if (has(get(object, 'aq_base', object), name)
and get(object, name) is o):
container = object
- if not securityManager.validate(object, container, name, o):
+ if not validate(object, container, name, o):
raise 'Unauthorized', name
else:
o=get(object, name, M)
if o is not M:
# Check security.
- if hasattr(object, 'aq_acquire'):
+ if has(object, 'aq_acquire'):
object.aq_acquire(
- name, validate2, securityManager.validate)
+ name, validate2, validate)
else:
- if not securityManager.validate(object, object, name, o):
+ if not validate(object, object, name, o):
raise 'Unauthorized', name
else:
try:
o=object[name]
except (AttributeError, TypeError):
raise AttributeError, name
- if not securityManager.validate(object, object, name, o):
+ if not validate(object, object, name, o):
raise 'Unauthorized', name
object = o
--- Updated File PageTemplate.py in package Packages/Products/PageTemplates --
--- PageTemplate.py 2001/05/18 18:13:02 1.11
+++ PageTemplate.py 2001/06/16 15:55:28 1.11.2.1
@@ -99,6 +99,8 @@
from cStringIO import StringIO
from ExtensionClass import Base
+Z_DEBUG_MODE = os.environ.get('Z_DEBUG_MODE') == '1'
+
class MacroCollection(Base):
def __of__(self, parent):
return parent._v_macros
@@ -145,7 +147,7 @@
output = StringIO()
c = self.pt_getContext()
c.update(extra_context)
- if __debug__:
+ if Z_DEBUG_MODE:
__traceback_info__ = pprint.pformat(c)
TALInterpreter(self._v_program, self._v_macros,
--- Updated File PageTemplateFile.py in package Packages/Products/PageTemplates --
--- Updated File PythonExpr.py in package Packages/Products/PageTemplates --
--- PythonExpr.py 2001/05/25 14:37:21 1.2.2.1
+++ PythonExpr.py 2001/06/16 15:55:28 1.2.2.2
@@ -117,10 +117,10 @@
def _bind_used_names(self, econtext):
# Bind template variables
names = {}
- var = econtext.contexts['var']
+ vars = econtext.vars
getType = econtext._engine.getTypes().get
for vname in self._f_varnames:
- has, val = var.has_get(vname)
+ has, val = vars.has_get(vname)
if not has:
has = val = getType(vname)
if has:
--- Updated File README.txt in package Packages/Products/PageTemplates --
--- README.txt 2001/03/29 10:21:26 1.1
+++ README.txt 2001/06/16 15:55:28 1.1.6.1
@@ -1,2 +1,4 @@
See <a href="http://dev.zope.org/Wikis/DevSite/Projects/ZPT">the
-ZPT project Wiki</a> for more information.
+ZPT project Wiki</a> for more information about Page Templates, or
+<a href="http://www.zope.org/Members/4am/ZPT">the download page</a>
+for installation instructions and the most recent version of the software.
--- Updated File TALES.py in package Packages/Products/PageTemplates --
--- TALES.py 2001/05/18 18:11:19 1.13
+++ TALES.py 2001/06/16 15:55:28 1.13.2.1
@@ -92,6 +92,8 @@
import re, sys, ZTUtils
from MultiMapping import MultiMapping
+StringType = type('')
+
NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*"
_parse_expr = re.compile(r"(%s):(.*)" % NAME_RE).match
_valid_name = re.compile('%s$' % NAME_RE).match
@@ -141,19 +143,13 @@
'''
__allow_access_to_unprotected_subobjects__ = 1
push = pop = None
- def _push(self, ob):
- MultiMapping.push(self, ob)
- def _pop(self, *args):
- if args:
- return apply(MultiMapping.pop, (self,) + args)
- else:
- return MultiMapping.pop(self)
- def has_get(self, key):
+
+ _push = MultiMapping.push
+ _pop = MultiMapping.pop
+
+ def has_get(self, key, _marker=[]):
v = self.get(key, _marker)
- if v is _marker:
- return 0, None
- else:
- return 1, v
+ return v is not _marker, v
class Iterator(ZTUtils.Iterator):
def __init__(self, name, seq, context):
@@ -234,83 +230,87 @@
contexts['nothing'] = None
contexts['default'] = Default
- # Keep track of what contexts get pushed as each scope begins.
- self._ctxts_pushed = []
- # These contexts will need to be pushed.
- self._current_ctxts = {'local': 1, 'repeat': 1}
-
- lv = self._context_class()
- init_local = contexts.get('local', None)
- if init_local:
- lv._push(init_local)
- contexts['local'] = lv
- contexts['repeat'] = rep = self._context_class()
+ self.repeat_vars = rv = {}
+ # Wrap this, as it is visible to restricted code
+ contexts['repeat'] = rep = self._context_class(rv)
contexts['loop'] = rep # alias
- contexts['global'] = gv = contexts.copy()
- contexts['var'] = self._context_class(gv, lv)
-
+
+ self.global_vars = gv = contexts.copy()
+ self.local_vars = lv = {}
+ self.vars = self._context_class(gv, lv)
+
+ # Keep track of what needs to be popped as each scope ends.
+ self._scope_stack = []
+
def beginScope(self):
- oldctxts = self._current_ctxts
- self._ctxts_pushed.append(oldctxts)
- self._current_ctxts = ctxts = {}
- for ctxname in oldctxts.keys():
- # Push fresh namespace on each local stack.
- ctxts[ctxname] = ctx = {}
- self.contexts[ctxname]._push(ctx)
+ self._scope_stack.append([self.local_vars.copy()])
def endScope(self):
- self._current_ctxts = ctxts = self._ctxts_pushed.pop()
- # Pop the ones that were pushed at the beginning of the scope.
- for ctxname in ctxts.keys():
- ctx = self.contexts[ctxname]._pop()
- # Make sure there's no circular garbage
- ctx.clear()
+ scope = self._scope_stack.pop()
+ self.local_vars = lv = scope[0]
+ v = self.vars
+ v._pop()
+ v._push(lv)
+ # Pop repeat variables, if any
+ i = len(scope) - 1
+ while i:
+ name, value = scope[i]
+ if value is None:
+ del self.repeat_vars[name]
+ else:
+ self.repeat_vars[name] = value
+ i = i - 1
def setLocal(self, name, value):
- self._current_ctxts['local'][name] = value
+ self.local_vars[name] = value
def setGlobal(self, name, value):
- self.contexts['global'][name] = value
+ self.global_vars[name] = value
def setRepeat(self, name, expr):
expr = self.evaluate(expr)
it = self._engine.Iterator(name, expr, self)
- self._current_ctxts['repeat'][name] = it
+ old_value = self.repeat_vars.get(name)
+ self._scope_stack[-1].append((name, old_value))
+ self.repeat_vars[name] = it
return it
- def evaluate(self, expression):
- if type(expression) is type(''):
+ def evaluate(self, expression,
+ isinstance=isinstance, StringType=StringType):
+ if isinstance(expression, StringType):
expression = self._engine.compile(expression)
try:
v = expression(self)
- if isinstance(v, Exception):
- raise v
- return v
except TALESError:
raise
except:
- if type(sys.exc_info()[0]) is type(''):
+ if sys.exc_info()[0] in ('Redirect', 'Unauthorized'):
raise
raise TALESError, (`expression`, sys.exc_info()), sys.exc_info()[2]
+ else:
+ if isinstance(v, Exception):
+ raise v
+ return v
evaluateValue = evaluate
def evaluateBoolean(self, expr):
- bool = self.evaluate(expr)
- return not not bool
+ return not not self.evaluate(expr)
- def evaluateText(self, expr):
+ def evaluateText(self, expr, None=None):
text = self.evaluate(expr)
- if text not in (None, Default):
- text = str(text)
- return text
+ if text is Default or text is None:
+ return text
+ return str(text)
def evaluateStructure(self, expr):
return self.evaluate(expr)
+ evaluateStructure = evaluate
def evaluateMacro(self, expr):
# XXX Should return None or a macro definition
return self.evaluate(expr)
+ evaluateMacro = evaluate
def getTALESError(self):
return TALESError
@@ -327,9 +327,4 @@
return self._name, self._expr
def __repr__(self):
return '<SimpleExpr %s %s>' % (self._name, `self._expr`)
-
-
-
-
-
--- Updated File ZPythonExpr.py in package Packages/Products/PageTemplates --
--- ZPythonExpr.py 2001/05/25 14:37:21 1.2.2.1
+++ ZPythonExpr.py 2001/06/16 15:55:28 1.2.2.2
@@ -128,7 +128,7 @@
td.this = None
td._push(ns['request'])
td._push(InstanceDict(ns['here'], td))
- td._push(ns['var'])
+ td._push(ns)
try:
if arg==2:
return f(None, td)
--- Updated File ZRPythonExpr.py in package Packages/Products/PageTemplates --
--- ZRPythonExpr.py 2001/05/25 14:37:21 1.2.2.1
+++ ZRPythonExpr.py 2001/06/16 15:55:28 1.2.2.2
@@ -133,7 +133,7 @@
td.this = None
td._push(ns['request'])
td._push(InstanceDict(ns['here'], td, full_read_guard))
- td._push(ns['var'])
+ td._push(ns)
try:
if arg==2:
return f(None, td)
--- Updated File ZopePageTemplate.py in package Packages/Products/PageTemplates --
--- Updated File version.txt in package Packages/Products/PageTemplates --
--- version.txt 2001/05/25 14:37:21 1.6.2.1
+++ version.txt 2001/06/16 15:55:28 1.6.2.2
@@ -1 +1 @@
-PageTemplates-1-3-1
+PageTemplates-1-3-2