Mercurial > p > roundup > code
changeset 2349:b43efe461b3e
update PageTemplates to latest Zope codebase
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Fri, 21 May 2004 05:56:46 +0000 |
| parents | 8c2402a78bb0 |
| children | 46d85c9622bb |
| files | roundup/cgi/PageTemplates/ComputedAttribute.py roundup/cgi/PageTemplates/Expressions.py roundup/cgi/PageTemplates/PageTemplate.py roundup/cgi/PageTemplates/PathIterator.py roundup/cgi/PageTemplates/PythonExpr.py roundup/cgi/PageTemplates/TALES.py roundup/cgi/PageTemplates/__init__.py |
| diffstat | 7 files changed, 144 insertions(+), 152 deletions(-) [+] |
line wrap: on
line diff
--- a/roundup/cgi/PageTemplates/ComputedAttribute.py Fri May 21 05:36:30 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -class ComputedAttribute: - def __init__(self, callable, level): - self.callable = callable - self.level = level - def __of__(self, *args): - if self.level > 0: - return self.callable - if isinstance(self.callable, type('')): - return getattr(args[0], self.callable) - return self.callable(*args) -
--- a/roundup/cgi/PageTemplates/Expressions.py Fri May 21 05:36:30 2004 +0000 +++ b/roundup/cgi/PageTemplates/Expressions.py Fri May 21 05:56:46 2004 +0000 @@ -1,37 +1,32 @@ ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE +# +############################################################################## +# Modified for Roundup: # -############################################################################## +# 1. Removed all Zope-specific code (doesn't even try to import that stuff now) +# 2. Removed all Acquisition """Page Template Expression Engine Page Template-specific implementation of TALES, with handlers for Python expressions, string literals, and paths. - - -Modified for Roundup 0.5 release: +""" -- Removed all Zope-specific code (doesn't even try to import that stuff now) -- Removed all Acquisition -- Made traceback info more informative - -""" -__docformat__ = 'restructuredtext' - -__version__='$Revision: 1.9 $'[11:-2] +__version__='$Revision: 1.10 $'[11:-2] import re, sys from TALES import Engine, CompilerError, _valid_name, NAME_RE, \ Undefined, Default, _parse_expr -from string import strip, split, join, replace, lstrip + _engine = None def getEngine(): @@ -53,10 +48,17 @@ reg('defer', DeferExpr) from PythonExpr import getSecurityManager, PythonExpr +guarded_getattr = getattr try: 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) @@ -70,6 +72,8 @@ __import__(module) return sys.modules[module] +SecureModuleImporter = _SecureModuleImporter() + Undefs = (Undefined, AttributeError, KeyError, TypeError, IndexError, Unauthorized) @@ -95,9 +99,9 @@ class SubPathExpr: def __init__(self, path): - self._path = path = split(strip(path), '/') + self._path = path = path.strip().split('/') self._base = base = path.pop(0) - if not _valid_name(base): + if base and not _valid_name(base): raise CompilerError, 'Invalid variable name "%s"' % base # Parse path self._dp = dp = [] @@ -123,7 +127,7 @@ path[i:i+1] = list(val) base = self._base __traceback_info__ = 'path expression "%s"'%('/'.join(self._path)) - if base == 'CONTEXTS': + if base == 'CONTEXTS' or not base: ob = econtext.contexts else: ob = vars[base] @@ -138,15 +142,15 @@ self._s = expr self._name = name self._hybrid = 0 - paths = split(expr, '|') + paths = expr.split('|') self._subexprs = [] add = self._subexprs.append for i in range(len(paths)): - path = lstrip(paths[i]) + path = paths[i].lstrip() if _parse_expr(path): # This part is the start of another expression type, # so glue it back together and compile it. - add(engine.compile(lstrip(join(paths[i:], '|')))) + add(engine.compile(('|'.join(paths[i:]).lstrip()))) self._hybrid = 1 break add(SubPathExpr(path)._eval) @@ -194,18 +198,18 @@ def __repr__(self): return '%s:%s' % (self._name, `self._s`) - -_interp = re.compile(r'\$(%(n)s)|\${(%(n)s(?:/%(n)s)*)}' % {'n': NAME_RE}) + +_interp = re.compile(r'\$(%(n)s)|\${(%(n)s(?:/[^}]*)*)}' % {'n': NAME_RE}) class StringExpr: def __init__(self, name, expr, engine): self._s = expr if '%' in expr: - expr = replace(expr, '%', '%%') + expr = expr.replace('%', '%%') self._vars = vars = [] if '$' in expr: parts = [] - for exp in split(expr, '$$'): + for exp in expr.split('$$'): if parts: parts.append('$') m = _interp.search(exp) while m is not None: @@ -219,15 +223,16 @@ raise CompilerError, ( '$ must be doubled or followed by a simple path') parts.append(exp) - expr = join(parts, '') + expr = ''.join(parts) self._expr = expr - + def __call__(self, econtext): vvals = [] for var in self._vars: v = var(econtext) - if isinstance(v, Exception): - raise v + # I hope this isn't in use anymore. + ## if isinstance(v, Exception): + ## raise v vvals.append(v) return self._expr % tuple(vvals) @@ -239,11 +244,14 @@ class NotExpr: def __init__(self, name, expr, compiler): - self._s = expr = lstrip(expr) + self._s = expr = expr.lstrip() self._c = compiler.compile(expr) - + def __call__(self, econtext): - return not econtext.evaluateBoolean(self._c) + # We use the (not x) and 1 or 0 formulation to avoid changing + # the representation of the result in Python 2.3, where the + # result of "not" becomes an instance of bool. + return (not econtext.evaluateBoolean(self._c)) and 1 or 0 def __repr__(self): return 'not:%s' % `self._s` @@ -261,53 +269,45 @@ class DeferExpr: def __init__(self, name, expr, compiler): - self._s = expr = lstrip(expr) + self._s = expr = expr.lstrip() self._c = compiler.compile(expr) - + def __call__(self, econtext): return DeferWrapper(self._c, econtext) def __repr__(self): return 'defer:%s' % `self._s` -class TraversalError: - def __init__(self, path, name): - self.path = path - self.name = name -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() - path.pop(0) - path.reverse() - object = self - #print 'TRAVERSE', (object, path) - done = [] + validate = securityManager.validate + __traceback_info__ = REQUEST while path: name = path.pop() - __traceback_info__ = TraversalError(done, name) + + if isinstance(name, TupleType): + object = object(*name) + continue -# if isinstance(name, TupleType): -# object = apply(object, name) -# continue - -# if name[0] == '_': -# # Never allowed in a URL. -# raise AttributeError, name + if not name: + # Skip directly to item access + o = object[name] + # Check access to the item. + if not validate(object, object, name, o): + raise Unauthorized, name + object = o + continue # Try an attribute. - o = get(object, name, M) -# print '...', (object, name, M, o) + o = guarded_getattr(object, name, M) if o is M: # Try an item. -# print '... try an item' try: # XXX maybe in Python 2.2 we can just check whether # the object has the attribute "__getitem__" @@ -319,18 +319,15 @@ # Try to re-raise the original attribute error. # XXX I think this only happens with # ExtensionClass instances. - get(object, name) + guarded_getattr(object, name) raise except TypeError, exc: if str(exc).find('unsubscriptable') >= 0: # The object does not support the item interface. # Try to re-raise the original attribute error. # XXX This is sooooo ugly. - get(object, name) + guarded_getattr(object, name) raise - #print '... object is now', `o` object = o - done.append((name, o)) return object -
--- a/roundup/cgi/PageTemplates/PageTemplate.py Fri May 21 05:36:30 2004 +0000 +++ b/roundup/cgi/PageTemplates/PageTemplate.py Fri May 21 05:56:46 2004 +0000 @@ -1,42 +1,40 @@ ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE +# +############################################################################## +# Modified for Roundup: # -############################################################################## +# 1. changed imports to import from roundup.cgi +# 2. removed use of ExtensionClass +# 3. removed use of ComputedAttribute """Page Template module HTML- and XML-based template objects using TAL, TALES, and METAL. - - -Modified for Roundup 0.5 release: +""" -- changed imports to import from roundup.cgi - -""" -__docformat__ = 'restructuredtext' - -__version__='$Revision: 1.4 $'[11:-2] +__version__='$Revision: 1.5 $'[11:-2] import sys from roundup.cgi.TAL.TALParser import TALParser from roundup.cgi.TAL.HTMLTALParser import HTMLTALParser from roundup.cgi.TAL.TALGenerator import TALGenerator -from roundup.cgi.TAL.TALInterpreter import TALInterpreter +# Do not use cStringIO here! It's not unicode aware. :( +from roundup.cgi.TAL.TALInterpreter import TALInterpreter, FasterStringIO from Expressions import getEngine -from string import join, strip, rstrip, split, replace, lower, find -from cStringIO import StringIO + class PageTemplate: "Page Templates using TAL, TALES, and METAL" - + content_type = 'text/html' expand = 0 _v_errors = () @@ -48,6 +46,11 @@ _text = '' _error_start = '<!-- Page Template Diagnostics' + def StringIO(self): + # Third-party products wishing to provide a full Unicode-aware + # StringIO can do so by monkey-patching this method. + return FasterStringIO() + def pt_edit(self, text, content_type): if content_type: self.content_type = str(content_type) @@ -71,7 +74,7 @@ parent = getattr(self, 'aq_parent', None) c['root'] = self return c - + def pt_render(self, source=0, extra_context={}): """Render this Page Template""" if not self._v_cooked: @@ -81,7 +84,7 @@ if self._v_errors: raise PTRuntimeError, 'Page Template %s has errors.' % self.id - output = StringIO() + output = self.StringIO() c = self.pt_getContext() c.update(extra_context) @@ -107,7 +110,7 @@ self.pt_render(source=1) except: return ('Macro expansion failed', '%s: %s' % sys.exc_info()[:2]) - + def pt_warnings(self): if not self._v_cooked: self._cook() @@ -132,7 +135,7 @@ def write(self, text): assert type(text) is type('') if text[:len(self._error_start)] == self._error_start: - errend = find(text, '-->') + errend = text.find('-->') if errend >= 0: text = text[errend + 4:] if self._text != text: @@ -140,8 +143,7 @@ self._cook() def read(self): - if not self._v_cooked: - self._cook() + self._cook_check() if not self._v_errors: if not self.expand: return self._text @@ -151,11 +153,15 @@ return ('%s\n Macro expansion failed\n %s\n-->\n%s' % (self._error_start, "%s: %s" % sys.exc_info()[:2], self._text) ) - + return ('%s\n %s\n-->\n%s' % (self._error_start, - join(self._v_errors, '\n '), + '\n '.join(self._v_errors), self._text)) + def _cook_check(self): + if not self._v_cooked: + self._cook() + def _cook(self): """Compile the TAL and METAL statments. @@ -187,7 +193,7 @@ class _ModuleImporter: def __getitem__(self, module): mod = __import__(module) - path = split(module, '.') + path = module.split('.') for name in path[1:]: mod = getattr(mod, name) return mod
--- a/roundup/cgi/PageTemplates/PathIterator.py Fri May 21 05:36:30 2004 +0000 +++ b/roundup/cgi/PageTemplates/PathIterator.py Fri May 21 05:56:46 2004 +0000 @@ -1,14 +1,14 @@ ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE -# +# ############################################################################## """Path Iterator @@ -16,13 +16,11 @@ A TALES Iterator with the ability to use first() and last() on subpaths of elements. """ -__docformat__ = 'restructuredtext' -__version__='$Revision: 1.2 $'[11:-2] +__version__='$Revision: 1.3 $'[11:-2] import TALES from Expressions import restrictedTraverse, Undefs, getSecurityManager -from string import split class Iterator(TALES.Iterator): def __bobo_traverse__(self, REQUEST, name): @@ -37,7 +35,7 @@ if name is None: return ob1 == ob2 if isinstance(name, type('')): - name = split(name, '/') + name = name.split('/') name = filter(None, name) securityManager = getSecurityManager() try: @@ -46,4 +44,3 @@ except Undefs: return 0 return ob1 == ob2 -
--- a/roundup/cgi/PageTemplates/PythonExpr.py Fri May 21 05:36:30 2004 +0000 +++ b/roundup/cgi/PageTemplates/PythonExpr.py Fri May 21 05:56:46 2004 +0000 @@ -1,29 +1,25 @@ ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE +# +############################################################################## +# Modified for Roundup: # -############################################################################## +# 1. more informative traceback info """Generic Python Expression Handler - -Modified for Roundup 0.5 release: - -- more informative traceback info +""" -""" -__docformat__ = 'restructuredtext' - -__version__='$Revision: 1.5 $'[11:-2] +__version__='$Revision: 1.6 $'[11:-2] from TALES import CompilerError -from string import strip, split, join, replace, lstrip from sys import exc_info class getSecurityManager: @@ -34,10 +30,10 @@ class PythonExpr: def __init__(self, name, expr, engine): - self.expr = expr = replace(strip(expr), '\n', ' ') + self.expr = expr = expr.strip().replace('\n', ' ') try: d = {} - exec 'def f():\n return %s\n' % strip(expr) in d + exec 'def f():\n return %s\n' % expr.strip() in d self._f = d['f'] except: raise CompilerError, ('Python expression error:\n' @@ -50,25 +46,26 @@ 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 = {} + names = {'CONTEXTS': econtext.contexts} vars = econtext.vars getType = econtext.getCompiler().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 def __call__(self, econtext): __traceback_info__ = 'python expression "%s"'%self.expr f = self._f - f.func_globals.update(self._bind_used_names(econtext)) + f.func_globals.update(self._bind_used_names(econtext)) return f() def __str__(self):
--- a/roundup/cgi/PageTemplates/TALES.py Fri May 21 05:36:30 2004 +0000 +++ b/roundup/cgi/PageTemplates/TALES.py Fri May 21 05:56:46 2004 +0000 @@ -1,30 +1,33 @@ ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE +# +############################################################################## +# Modified for Roundup: # -############################################################################## +# 1. changed imports to import from roundup.cgi +# 2. implemented ustr as atr """TALES An implementation of a generic TALES engine - -Modified for Roundup 0.5 release: +""" -- changed imports to import from roundup.cgi -""" -__docformat__ = 'restructuredtext' - -__version__='$Revision: 1.6 $'[11:-2] +__version__='$Revision: 1.7 $'[11:-2] import re, sys from roundup.cgi import ZTUtils +from weakref import ref from MultiMapping import MultiMapping +from GlobalTranslationService import getGlobalTranslationService + +ustr = str StringType = type('') @@ -48,8 +51,6 @@ '''Retain Default''' Default = Default() -_marker = [] - class SafeMapping(MultiMapping): '''Mapping with security declarations and limited method exposure. @@ -64,19 +65,18 @@ _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): ZTUtils.Iterator.__init__(self, seq) self.name = name - self._context = context + self._context_ref = ref(context) def next(self): if ZTUtils.Iterator.next(self): - self._context.setLocal(self.name, self.item) + context = self._context_ref() + if context is not None: + context.setLocal(self.name, self.item) return 1 return 0 @@ -138,7 +138,7 @@ raise CompilerError, ( 'Unrecognized expression type "%s".' % type) return handler(type, expr, self) - + def getContext(self, contexts=None, **kwcontexts): if contexts is not None: if kwcontexts: @@ -223,8 +223,7 @@ expression = self._compiler.compile(expression) __traceback_supplement__ = ( TALESTracebackSupplement, self, expression) - v = expression(self) - return v + return expression(self) evaluateValue = evaluate evaluateBoolean = evaluate @@ -233,7 +232,10 @@ text = self.evaluate(expr) if text is Default or text is None: return text - return str(text) + if isinstance(text, unicode): + return text + else: + return ustr(text) def evaluateStructure(self, expr): return self.evaluate(expr) @@ -256,7 +258,15 @@ def setPosition(self, position): self.position = position - + def translate(self, domain, msgid, mapping=None, + context=None, target_language=None, default=None): + if context is None: + context = self.contexts.get('here') + return getGlobalTranslationService().translate( + domain, msgid, mapping=mapping, + context=context, + default=default, + target_language=target_language) class TALESTracebackSupplement: """Implementation of ITracebackSupplement""" @@ -272,12 +282,10 @@ data = self.context.contexts.copy() s = pprint.pformat(data) if not as_html: - return ' - Names:\n %s' % string.replace(s, '\n', '\n ') + return ' - Names:\n %s' % s.replace('\n', '\n ') else: from cgi import escape return '<b>Names:</b><pre>%s</pre>' % (escape(s)) - return None - class SimpleExpr: @@ -289,4 +297,3 @@ return self._name, self._expr def __repr__(self): return '<SimpleExpr %s %s>' % (self._name, `self._expr`) -
--- a/roundup/cgi/PageTemplates/__init__.py Fri May 21 05:36:30 2004 +0000 +++ b/roundup/cgi/PageTemplates/__init__.py Fri May 21 05:56:46 2004 +0000 @@ -1,22 +1,21 @@ ############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE -# +# ############################################################################## __doc__='''Package wrapper for Page Templates This wrapper allows the Page Template modules to be segregated in a separate package. -$Id: __init__.py,v 1.2 2004-02-11 23:55:09 richard Exp $''' -__docformat__ = 'restructuredtext' +$Id: __init__.py,v 1.3 2004-05-21 05:56:46 richard Exp $''' __version__='$$'[11:-2]
