zope.tales-3.5.3/0000775000177100020040000000000012060151477014737 5ustar menesismenesis00000000000000zope.tales-3.5.3/README.txt0000664000177100020040000000016612060151463016433 0ustar menesismenesis00000000000000Overview ======== Template Attribute Language - Expression Syntax See http://wiki.zope.org/ZPT/TALESSpecification13 zope.tales-3.5.3/src/0000775000177100020040000000000012060151477015526 5ustar menesismenesis00000000000000zope.tales-3.5.3/src/zope/0000775000177100020040000000000012060151477016503 5ustar menesismenesis00000000000000zope.tales-3.5.3/src/zope/tales/0000775000177100020040000000000012060151477017613 5ustar menesismenesis00000000000000zope.tales-3.5.3/src/zope/tales/expressions.py0000664000177100020040000002630412060151463022547 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Basic Page Template expression types. $Id: expressions.py 126816 2012-06-11 19:00:21Z tseaver $ """ import re, types from zope.interface import implements from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined from zope.tales.interfaces import ITALESExpression, ITALESFunctionNamespace Undefs = (Undefined, AttributeError, LookupError, TypeError) _marker = object() namespace_re = re.compile(r'(\w+):(.+)') def simpleTraverse(object, path_items, econtext): """Traverses a sequence of names, first trying attributes then items. """ for name in path_items: next = getattr(object, name, _marker) if next is not _marker: object = next elif hasattr(object, '__getitem__'): object = object[name] else: # Allow AttributeError to propagate object = getattr(object, name) return object class SubPathExpr(object): def __init__(self, path, traverser, engine): self._traverser = traverser self._engine = engine # Parse path compiledpath = [] currentpath = [] for element in str(path).strip().split('/'): if not element: raise engine.getCompilerError()( 'Path element may not be empty in %r' % path) if element.startswith('?'): if currentpath: compiledpath.append(tuple(currentpath)) currentpath = [] if not _valid_name(element[1:]): raise engine.getCompilerError()( 'Invalid variable name "%s"' % element[1:]) compiledpath.append(element[1:]) else: match = namespace_re.match(element) if match: if currentpath: compiledpath.append(tuple(currentpath)) currentpath = [] namespace, functionname = match.groups() if not _valid_name(namespace): raise engine.getCompilerError()( 'Invalid namespace name "%s"' % namespace) try: compiledpath.append( self._engine.getFunctionNamespace(namespace)) except KeyError: raise engine.getCompilerError()( 'Unknown namespace "%s"' % namespace) currentpath.append(functionname) else: currentpath.append(element) if currentpath: compiledpath.append(tuple(currentpath)) first = compiledpath[0] base = first[0] if callable(first): # check for initial function raise engine.getCompilerError()( 'Namespace function specified in first subpath element') elif isinstance(first, basestring): # check for initial ? raise engine.getCompilerError()( 'Dynamic name specified in first subpath element') if base and not _valid_name(base): raise engine.getCompilerError()( 'Invalid variable name "%s"' % element) self._base = base compiledpath[0] = first[1:] self._compiled_path = tuple(compiledpath) def _eval(self, econtext, isinstance=isinstance): vars = econtext.vars compiled_path = self._compiled_path base = self._base if base == 'CONTEXTS' or not base: # Special base name ob = econtext.contexts else: ob = vars[base] if isinstance(ob, DeferWrapper): ob = ob() for element in compiled_path: if isinstance(element, tuple): ob = self._traverser(ob, element, econtext) elif isinstance(element, basestring): val = vars[element] # If the value isn't a string, assume it's a sequence # of path names. if isinstance(val, basestring): val = (val,) ob = self._traverser(ob, val, econtext) elif callable(element): ob = element(ob) # TODO: Once we have n-ary adapters, use them. if ITALESFunctionNamespace.providedBy(ob): ob.setEngine(econtext) else: raise ValueError(repr(element)) return ob class PathExpr(object): """One or more subpath expressions, separated by '|'.""" implements(ITALESExpression) # _default_type_names contains the expression type names this # class is usually registered for. _default_type_names = ( 'standard', 'path', 'exists', 'nocall', ) def __init__(self, name, expr, engine, traverser=simpleTraverse): self._s = expr self._name = name self._hybrid = False paths = expr.split('|') self._subexprs = [] add = self._subexprs.append for i in range(len(paths)): 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('|'.join(paths[i:]).lstrip())) self._hybrid = True break add(SubPathExpr(path, traverser, engine)._eval) def _exists(self, econtext): for expr in self._subexprs: try: expr(econtext) except Undefs: pass else: return 1 return 0 def _eval(self, econtext): for expr in self._subexprs[:-1]: # Try all but the last subexpression, skipping undefined ones. try: ob = expr(econtext) except Undefs: pass else: break else: # On the last subexpression allow exceptions through, and # don't autocall if the expression was not a subpath. ob = self._subexprs[-1](econtext) if self._hybrid: return ob if self._name == 'nocall': return ob # Call the object if it is callable. Note that checking for # callable() isn't safe because the object might be security # proxied (and security proxies report themselves callable, no # matter what the underlying object is). We therefore check # for the __call__ attribute, but not with hasattr as that # eats babies, err, exceptions. In addition to that, we # support calling old style classes which don't have a # __call__. if (getattr(ob, '__call__', _marker) is not _marker or isinstance(ob, types.ClassType)): return ob() return ob def __call__(self, econtext): if self._name == 'exists': return self._exists(econtext) return self._eval(econtext) def __str__(self): return '%s expression (%s)' % (self._name, `self._s`) def __repr__(self): return '' % (self._name, `self._s`) _interp = re.compile( r'\$(%(n)s)|\${(%(n)s(?:/[^}|]*)*(?:\|%(n)s(?:/[^}|]*)*)*)}' % {'n': NAME_RE}) class StringExpr(object): implements(ITALESExpression) def __init__(self, name, expr, engine): self._s = expr if '%' in expr: expr = expr.replace('%', '%%') self._vars = vars = [] if '$' in expr: # Use whatever expr type is registered as "path". path_type = engine.getTypes()['path'] parts = [] for exp in expr.split('$$'): if parts: parts.append('$') m = _interp.search(exp) while m is not None: parts.append(exp[:m.start()]) parts.append('%s') vars.append(path_type( 'path', m.group(1) or m.group(2), engine)) exp = exp[m.end():] m = _interp.search(exp) if '$' in exp: raise engine.getCompilerError()( '$ must be doubled or followed by a simple path') parts.append(exp) expr = ''.join(parts) self._expr = expr def __call__(self, econtext): vvals = [] for var in self._vars: v = var(econtext) vvals.append(v) return self._expr % tuple(vvals) def __str__(self): return 'string expression (%s)' % `self._s` def __repr__(self): return '' % `self._s` class NotExpr(object): implements(ITALESExpression) def __init__(self, name, expr, engine): self._s = expr = expr.lstrip() self._c = engine.compile(expr) def __call__(self, econtext): return int(not econtext.evaluateBoolean(self._c)) def __repr__(self): return '' % `self._s` class DeferWrapper(object): def __init__(self, expr, econtext): self._expr = expr self._econtext = econtext def __str__(self): return str(self()) def __call__(self): return self._expr(self._econtext) class DeferExpr(object): implements(ITALESExpression) def __init__(self, name, expr, compiler): self._s = expr = expr.lstrip() self._c = compiler.compile(expr) def __call__(self, econtext): return DeferWrapper(self._c, econtext) def __repr__(self): return '' % `self._s` class LazyWrapper(DeferWrapper): """Wrapper for lazy: expression """ def __init__(self, expr, econtext): DeferWrapper.__init__(self, expr, econtext) self._result = _marker def __call__(self): r = self._result if r is _marker: self._result = r = self._expr(self._econtext) return r class LazyExpr(DeferExpr): """lazy: expression handler for lazy initialization of expressions """ def __call__(self, econtext): return LazyWrapper(self._c, econtext) def __repr__(self): return 'lazy:%s' % `self._s` class SimpleModuleImporter(object): """Minimal module importer with no security.""" def __getitem__(self, module): mod = self._get_toplevel_module(module) path = module.split('.') for name in path[1:]: mod = getattr(mod, name) return mod def _get_toplevel_module(self, module): # This can be overridden to add security proxies. return __import__(module) zope.tales-3.5.3/src/zope/tales/tales.py0000664000177100020040000005050612060151463021276 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """TALES An implementation of a TAL expression engine $Id: tales.py 126816 2012-06-11 19:00:21Z tseaver $ """ __docformat__ = "reStructuredText" import re from zope.interface import implements try: from zope import tal except ImportError: tal = None if tal: from zope.tal.interfaces import ITALExpressionEngine from zope.tal.interfaces import ITALExpressionCompiler from zope.tal.interfaces import ITALExpressionErrorInfo from zope.tales.interfaces import ITALESIterator 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 class TALESError(Exception): """Error during TALES evaluation""" class Undefined(TALESError): '''Exception raised on traversal of an undefined path''' class CompilerError(Exception): '''TALES Compiler Error''' class RegistrationError(Exception): '''Expression type or base name registration Error''' _default = object() class Iterator(object): """TALES Iterator """ if tal: implements(ITALESIterator) def __init__(self, name, seq, context): """Construct an iterator Iterators are defined for a name, a sequence, or an iterator and a context, where a context simply has a setLocal method: >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) A local variable is not set until the iterator is used: >>> int("foo" in context.vars) 0 We can create an iterator on an empty sequence: >>> it = Iterator('foo', (), context) An iterator works as well: >>> it = Iterator('foo', {"apple":1, "pear":1, "orange":1}, context) >>> it.next() True >>> it = Iterator('foo', {}, context) >>> it.next() False >>> it = Iterator('foo', iter((1, 2, 3)), context) >>> it.next() True >>> it.next() True """ self._seq = seq self._iter = i = iter(seq) self._nextIndex = 0 self._name = name self._setLocal = context.setLocal # This is tricky. We want to know if we are on the last item, # but we can't know that without trying to get it. :( self._last = False try: self._next = i.next() except StopIteration: self._done = True else: self._done = False def next(self): """Advance the iterator, if possible. >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> bool(it.next()) True >>> context.vars['foo'] 'apple' >>> bool(it.next()) True >>> context.vars['foo'] 'pear' >>> bool(it.next()) True >>> context.vars['foo'] 'orange' >>> bool(it.next()) False >>> it = Iterator('foo', {"apple":1, "pear":1, "orange":1}, context) >>> bool(it.next()) True >>> bool(it.next()) True >>> bool(it.next()) True >>> bool(it.next()) False >>> it = Iterator('foo', (), context) >>> bool(it.next()) False >>> it = Iterator('foo', {}, context) >>> bool(it.next()) False If we can advance, set a local variable to the new value. """ # Note that these are *NOT* Python iterators! if self._done: return False self._item = v = self._next try: self._next = self._iter.next() except StopIteration: self._done = True self._last = True self._nextIndex += 1 self._setLocal(self._name, v) return True def index(self): """Get the iterator index >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> int(bool(it.next())) 1 >>> it.index() 0 >>> int(bool(it.next())) 1 >>> it.index() 1 >>> int(bool(it.next())) 1 >>> it.index() 2 """ index = self._nextIndex - 1 if index < 0: raise TypeError("No iteration position") return index def number(self): """Get the iterator position >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> int(bool(it.next())) 1 >>> it.number() 1 >>> int(bool(it.next())) 1 >>> it.number() 2 >>> int(bool(it.next())) 1 >>> it.number() 3 """ return self._nextIndex def even(self): """Test whether the position is even >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.even() True >>> it.next() True >>> it.even() False >>> it.next() True >>> it.even() True """ return not ((self._nextIndex - 1) % 2) def odd(self): """Test whether the position is odd >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.odd() False >>> it.next() True >>> it.odd() True >>> it.next() True >>> it.odd() False """ return bool((self._nextIndex - 1) % 2) def parity(self): """Return 'odd' or 'even' depending on the position's parity >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.parity() 'odd' >>> it.next() True >>> it.parity() 'even' >>> it.next() True >>> it.parity() 'odd' """ if self._nextIndex % 2: return 'odd' return 'even' def letter(self, base=ord('a'), radix=26): """Get the iterator position as a lower-case letter >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.letter() 'a' >>> it.next() True >>> it.letter() 'b' >>> it.next() True >>> it.letter() 'c' """ index = self._nextIndex - 1 if index < 0: raise TypeError("No iteration position") s = '' while 1: index, off = divmod(index, radix) s = chr(base + off) + s if not index: return s def Letter(self): """Get the iterator position as an upper-case letter >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.Letter() 'A' >>> it.next() True >>> it.Letter() 'B' >>> it.next() True >>> it.Letter() 'C' """ return self.letter(base=ord('A')) def Roman(self, rnvalues=( (1000,'M'),(900,'CM'),(500,'D'),(400,'CD'), (100,'C'),(90,'XC'),(50,'L'),(40,'XL'), (10,'X'),(9,'IX'),(5,'V'),(4,'IV'),(1,'I')) ): """Get the iterator position as an upper-case roman numeral >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.Roman() 'I' >>> it.next() True >>> it.Roman() 'II' >>> it.next() True >>> it.Roman() 'III' """ n = self._nextIndex s = '' for v, r in rnvalues: rct, n = divmod(n, v) s = s + r * rct return s def roman(self): """Get the iterator position as a lower-case roman numeral >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.roman() 'i' >>> it.next() True >>> it.roman() 'ii' >>> it.next() True >>> it.roman() 'iii' """ return self.Roman().lower() def start(self): """Test whether the position is the first position >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.start() True >>> it.next() True >>> it.start() False >>> it.next() True >>> it.start() False >>> it = Iterator('foo', {}, context) >>> it.start() False >>> it.next() False >>> it.start() False """ return self._nextIndex == 1 def end(self): """Test whether the position is the last position >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.end() False >>> it.next() True >>> it.end() False >>> it.next() True >>> it.end() True >>> it = Iterator('foo', {}, context) >>> it.end() False >>> it.next() False >>> it.end() False """ return self._last def item(self): """Get the iterator value >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.next() True >>> it.item() 'apple' >>> it.next() True >>> it.item() 'pear' >>> it.next() True >>> it.item() 'orange' >>> it = Iterator('foo', {1:2}, context) >>> it.next() True >>> it.item() 1 """ if self._nextIndex == 0: raise TypeError("No iteration position") return self._item def length(self): """Get the length of the iterator sequence >>> context = Context(ExpressionEngine(), {}) >>> it = Iterator('foo', ("apple", "pear", "orange"), context) >>> it.length() 3 You can even get the length of a mapping: >>> it = Iterator('foo', {"apple":1, "pear":2, "orange":3}, context) >>> it.length() 3 But you can't get the length of an iterable which doesn't support len(): >>> class MyIter(object): ... def __init__(self, seq): ... self._next = iter(seq).next ... def __iter__(self): ... return self ... def next(self): ... return self._next() >>> it = Iterator('foo', MyIter({"apple":1, "pear":2}), context) >>> it.length() Traceback (most recent call last): ... TypeError: len() of unsized object """ return len(self._seq) class ErrorInfo(object): """Information about an exception passed to an on-error handler.""" if tal: implements(ITALExpressionErrorInfo) def __init__(self, err, position=(None, None)): if isinstance(err, Exception): self.type = err.__class__ self.value = err else: self.type = err self.value = None self.lineno = position[0] self.offset = position[1] class ExpressionEngine(object): '''Expression Engine An instance of this class keeps a mutable collection of expression type handlers. It can compile expression strings by delegating to these handlers. It can provide an expression Context, which is capable of holding state and evaluating compiled expressions. ''' if tal: implements(ITALExpressionCompiler) def __init__(self): self.types = {} self.base_names = {} self.namespaces = {} self.iteratorFactory = Iterator def registerFunctionNamespace(self, namespacename, namespacecallable): """Register a function namespace namespace - a string containing the name of the namespace to be registered namespacecallable - a callable object which takes the following parameter: context - the object on which the functions provided by this namespace will be called This callable should return an object which can be traversed to get the functions provided by the this namespace. example: class stringFuncs(object): def __init__(self,context): self.context = str(context) def upper(self): return self.context.upper() def lower(self): return self.context.lower() engine.registerFunctionNamespace('string',stringFuncs) """ self.namespaces[namespacename] = namespacecallable def getFunctionNamespace(self, namespacename): """ Returns the function namespace """ return self.namespaces[namespacename] def registerType(self, name, handler): if not _valid_name(name): raise RegistrationError('Invalid expression type name "%s".' % name) types = self.types if name in types: raise RegistrationError( 'Multiple registrations for Expression type "%s".' % name) types[name] = handler def getTypes(self): return self.types def registerBaseName(self, name, object): if not _valid_name(name): raise RegistrationError('Invalid base name "%s".' % name) base_names = self.base_names if name in base_names: raise RegistrationError( 'Multiple registrations for base name "%s".' % name) base_names[name] = object def getBaseNames(self): return self.base_names def compile(self, expression): m = _parse_expr(expression) if m: type = m.group(1) expr = expression[m.end():] else: type = "standard" expr = expression try: handler = self.types[type] except KeyError: 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: kwcontexts.update(contexts) else: kwcontexts = contexts return Context(self, kwcontexts) def getCompilerError(self): return CompilerError class Context(object): '''Expression Context An instance of this class holds context information that it can use to evaluate compiled expressions. ''' if tal: implements(ITALExpressionEngine) position = (None, None) source_file = None def __init__(self, engine, contexts): self._engine = engine self.contexts = contexts self.setContext('nothing', None) self.setContext('default', _default) self.repeat_vars = rv = {} # Wrap this, as it is visible to restricted code self.setContext('repeat', rv) self.setContext('loop', rv) # alias self.vars = vars = contexts.copy() self._vars_stack = [vars] # Keep track of what needs to be popped as each scope ends. self._scope_stack = [] def setContext(self, name, value): # Hook to allow subclasses to do things like adding security proxies self.contexts[name] = value def beginScope(self): self.vars = vars = self.vars.copy() self._vars_stack.append(vars) self._scope_stack.append([]) def endScope(self): self._vars_stack.pop() self.vars = self._vars_stack[-1] scope = self._scope_stack.pop() # Pop repeat variables, if any i = len(scope) while i: i = i - 1 name, value = scope[i] if value is None: del self.repeat_vars[name] else: self.repeat_vars[name] = value def setLocal(self, name, value): self.vars[name] = value def setGlobal(self, name, value): for vars in self._vars_stack: vars[name] = value def getValue(self, name, default=None): value = default for vars in self._vars_stack: value = vars.get(name, default) if value is not default: break return value def setRepeat(self, name, expr): expr = self.evaluate(expr) if not expr: return self._engine.iteratorFactory(name, (), self) it = self._engine.iteratorFactory(name, expr, self) 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 isinstance(expression, str): expression = self._engine.compile(expression) __traceback_supplement__ = ( TALESTracebackSupplement, self, expression) return expression(self) evaluateValue = evaluate def evaluateBoolean(self, expr): return not not self.evaluate(expr) def evaluateText(self, expr): text = self.evaluate(expr) if text is self.getDefault() or text is None: return text if isinstance(text, basestring): # text could already be something text-ish, e.g. a Message object return text return unicode(text) def evaluateStructure(self, expr): return self.evaluate(expr) evaluateStructure = evaluate def evaluateMacro(self, expr): # TODO: Should return None or a macro definition return self.evaluate(expr) evaluateMacro = evaluate def createErrorInfo(self, err, position): return ErrorInfo(err, position) def getDefault(self): return _default def setSourceFile(self, source_file): self.source_file = source_file def setPosition(self, position): self.position = position def translate(self, msgid, domain=None, mapping=None, default=None): # custom Context implementations are supposed to customize # this to call whichever translation routine they want to use return unicode(msgid) class TALESTracebackSupplement(object): """Implementation of zope.exceptions.ITracebackSupplement""" def __init__(self, context, expression): self.context = context self.source_url = context.source_file self.line = context.position[0] self.column = context.position[1] self.expression = repr(expression) def getInfo(self, as_html=0): import pprint data = self.context.contexts.copy() if 'modules' in data: del data['modules'] # the list is really long and boring s = pprint.pformat(data) if not as_html: return ' - Names:\n %s' % s.replace('\n', '\n ') else: from cgi import escape return 'Names:
%s
' % (escape(s)) return None zope.tales-3.5.3/src/zope/tales/pythonexpr.py0000664000177100020040000000542412060151463022405 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Generic Python Expression Handler $Id: pythonexpr.py 126816 2012-06-11 19:00:21Z tseaver $ """ class PythonExpr(object): def __init__(self, name, expr, engine): text = '\n'.join(expr.splitlines()) # normalize line endings text = '(' + text + ')' # Put text in parens so newlines don't matter self.text = text try: code = self._compile(text, '') except SyntaxError, e: raise engine.getCompilerError()(str(e)) self._code = code self._varnames = code.co_names def _compile(self, text, filename): return compile(text, filename, 'eval') def _bind_used_names(self, econtext, builtins): # Construct a dictionary of globals with which the Python # expression should be evaluated. names = {} vars = econtext.vars marker = self if not isinstance(builtins, dict): builtins = builtins.__dict__ for vname in self._varnames: val = vars.get(vname, marker) if val is not marker: names[vname] = val elif vname not in builtins: # Fall back to using expression types as variable values. val = econtext._engine.getTypes().get(vname, marker) if val is not marker: val = ExprTypeProxy(vname, val, econtext) names[vname] = val names['__builtins__'] = builtins return names def __call__(self, econtext): __traceback_info__ = self.text vars = self._bind_used_names(econtext, __builtins__) return eval(self._code, vars) def __str__(self): return 'Python expression "%s"' % self.text def __repr__(self): return '' % self.text class ExprTypeProxy(object): '''Class that proxies access to an expression type handler''' def __init__(self, name, handler, econtext): self._name = name self._handler = handler self._econtext = econtext def __call__(self, text): return self._handler(self._name, text, self._econtext._engine)(self._econtext) zope.tales-3.5.3/src/zope/tales/__init__.py0000664000177100020040000000136212060151463021721 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Template Attribute Language - Expression Syntax $Id: __init__.py 126816 2012-06-11 19:00:21Z tseaver $ """ zope.tales-3.5.3/src/zope/tales/interfaces.py0000664000177100020040000000704112060151463022305 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Interface that describes the 'macros' attribute of a PageTemplate. $Id: interfaces.py 126816 2012-06-11 19:00:21Z tseaver $ """ from zope.interface import Interface try: from zope import tal except ImportError: tal = None class ITALESFunctionNamespace(Interface): """Function namespaces can be used in TALES path expressions to extract information in non-default ways.""" def setEngine(engine): """Sets the engine that is used to evaluate TALES expressions.""" class ITALESExpression(Interface): """TALES expression These are expression handlers that handle a specific type of expression in TALES, e.g. path or string expression. """ def __call__(econtext): """Evaluate expression according to the given execution context 'econtext' and return computed value. """ if tal is not None: from zope.tal.interfaces import ITALIterator class ITALESIterator(ITALIterator): """TAL Iterator provided by TALES Values of this iterator are assigned to items in the repeat namespace. For example, with a TAL statement like: tal:repeat="item items", an iterator will be assigned to "repeat/item". The iterator provides a number of handy methods useful in writing TAL loops. The results are undefined of calling any of the methods except 'length' before the first iteration. """ def index(): """Return the position (starting with "0") within the iteration """ def number(): """Return the position (starting with "1") within the iteration """ def even(): """Return whether the current position is even """ def odd(): """Return whether the current position is odd """ def parity(): """Return 'odd' or 'even' depending on the position's parity Useful for assigning CSS class names to table rows. """ def start(): """Return whether the current position is the first position """ def end(): """Return whether the current position is the last position """ def letter(): """Return the position (starting with "a") within the iteration """ def Letter(): """Return the position (starting with "A") within the iteration """ def roman(): """Return the position (starting with "i") within the iteration """ def Roman(): """Return the position (starting with "I") within the iteration """ def item(): """Return the item at the current position """ def length(): """Return the length of the sequence Note that this may fail if the TAL iterator was created on a Python iterator. """ zope.tales-3.5.3/src/zope/tales/tests/0000775000177100020040000000000012060151477020755 5ustar menesismenesis00000000000000zope.tales-3.5.3/src/zope/tales/tests/test_traverser.py0000664000177100020040000000771112060151463024404 0ustar menesismenesis00000000000000""" Tests for zope.tales.expressions.simpleTraverse $Id: test_traverser.py 40270 2005-11-20 13:23:13Z shh $ """ from unittest import TestCase, TestSuite, makeSuite, main from zope.tales.expressions import simpleTraverse class AttrTraversable(object): """Traversable by attribute access""" attr = 'foo' class ItemTraversable(object): """Traversable by item access""" def __getitem__(self, name): if name == 'attr': return 'foo' raise KeyError, name class AllTraversable(AttrTraversable, ItemTraversable): """Traversable by attribute and item access""" pass _marker = object() def getitem(ob, name, default=_marker): """Helper a la getattr(ob, name, default).""" try: item = ob[name] except KeyError: if default is not _marker: return default raise KeyError, name else: return item class TraverserTests(TestCase): def testGetItem(self): # getitem helper should behave like __getitem__ ob = {'attr': 'foo'} self.assertEqual(getitem(ob, 'attr', None), 'foo') self.assertEqual(getitem(ob, 'attr'), 'foo') self.assertEqual(getitem(ob, 'missing_attr', None), None) self.assertRaises(KeyError, getitem, ob, 'missing_attr') self.assertRaises(TypeError, getitem, object(), 'attr') def testAttrTraversable(self): # An object without __getitem__ should raise AttributeError # for missing attribute. ob = AttrTraversable() self.assertEqual(getattr(ob, 'attr', None), 'foo') self.assertRaises(AttributeError, getattr, ob, 'missing_attr') def testItemTraversable(self): # An object with __getitem__ (but without attr) should raise # KeyError for missing attribute. ob = ItemTraversable() self.assertEqual(getitem(ob, 'attr', None), 'foo') self.assertRaises(KeyError, getitem, ob, 'missing_attr') def testAllTraversable(self): # An object with attr and __getitem__ should raise either # exception, depending on method of access. ob = AllTraversable() self.assertEqual(getattr(ob, 'attr', None), 'foo') self.assertRaises(AttributeError, getattr, ob, 'missing_attr') self.assertEqual(getitem(ob, 'attr', None), 'foo') self.assertRaises(KeyError, getitem, ob, 'missing_attr') def testTraverseEmptyPath(self): # simpleTraverse should return the original object if the path is emtpy ob = object() self.assertEqual(simpleTraverse(ob, [], None), ob) def testTraverseByAttr(self): # simpleTraverse should find attr through attribute access ob = AttrTraversable() self.assertEqual(simpleTraverse(ob, ['attr'], None), 'foo') def testTraverseByMissingAttr(self): # simpleTraverse should raise AttributeError ob = AttrTraversable() # Here lurks the bug (unexpected NamError raised) self.assertRaises(AttributeError, simpleTraverse, ob, ['missing_attr'], None) def testTraverseByItem(self): # simpleTraverse should find attr through item access ob = ItemTraversable() self.assertEqual(simpleTraverse(ob, ['attr'], None), 'foo') def testTraverseByMissingItem(self): # simpleTraverse should raise KeyError ob = ItemTraversable() self.assertRaises(KeyError, simpleTraverse, ob, ['missing_attr'], None) def testTraverseByAll(self): # simpleTraverse should find attr through attribute access ob = AllTraversable() self.assertEqual(simpleTraverse(ob, ['attr'], None), 'foo') def testTraverseByMissingAll(self): # simpleTraverse should raise KeyError (because ob implements __getitem__) ob = AllTraversable() self.assertRaises(KeyError, simpleTraverse, ob, ['missing_attr'], None) def test_suite(): return TestSuite(( makeSuite(TraverserTests), )) if __name__ == '__main__': main(defaultTest='test_suite') zope.tales-3.5.3/src/zope/tales/tests/test_tales.py0000664000177100020040000001367712060151463023507 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """TALES Tests $Id: test_tales.py 126816 2012-06-11 19:00:21Z tseaver $ """ import unittest import re from zope.tales import tales from zope.tales.tests.simpleexpr import SimpleExpr from doctest import DocTestSuite from zope.testing import renormalizing class TALESTests(unittest.TestCase): def testIterator0(self): # Test sample Iterator class context = Harness(self) it = tales.Iterator('name', (), context) self.assert_( not it.next(), "Empty iterator") context._complete_() def testIterator1(self): # Test sample Iterator class context = Harness(self) it = tales.Iterator('name', (1,), context) context._assert_('setLocal', 'name', 1) self.assert_( it.next() and not it.next(), "Single-element iterator") context._complete_() def testIterator2(self): # Test sample Iterator class context = Harness(self) it = tales.Iterator('text', 'text', context) for c in 'text': context._assert_('setLocal', 'text', c) for c in 'text': self.assert_(it.next(), "Multi-element iterator") self.assert_( not it.next(), "Multi-element iterator") context._complete_() def testRegisterType(self): # Test expression type registration e = tales.ExpressionEngine() e.registerType('simple', SimpleExpr) self.assert_( e.getTypes()['simple'] == SimpleExpr) def testRegisterTypeUnique(self): # Test expression type registration uniqueness e = tales.ExpressionEngine() e.registerType('simple', SimpleExpr) try: e.registerType('simple', SimpleExpr) except tales.RegistrationError: pass else: self.assert_( 0, "Duplicate registration accepted.") def testRegisterTypeNameConstraints(self): # Test constraints on expression type names e = tales.ExpressionEngine() for name in '1A', 'A!', 'AB ': try: e.registerType(name, SimpleExpr) except tales.RegistrationError: pass else: self.assert_( 0, 'Invalid type name "%s" accepted.' % name) def testCompile(self): # Test expression compilation e = tales.ExpressionEngine() e.registerType('simple', SimpleExpr) ce = e.compile('simple:x') self.assert_( ce(None) == ('simple', 'x'), ( 'Improperly compiled expression %s.' % `ce`)) def testGetContext(self): # Test Context creation tales.ExpressionEngine().getContext() tales.ExpressionEngine().getContext(v=1) tales.ExpressionEngine().getContext(x=1, y=2) def getContext(self, **kws): e = tales.ExpressionEngine() e.registerType('simple', SimpleExpr) return apply(e.getContext, (), kws) def testContext0(self): # Test use of Context se = self.getContext().evaluate('simple:x') self.assert_( se == ('simple', 'x'), ( 'Improperly evaluated expression %s.' % `se`)) def testVariables(self): # Test variables ctxt = self.getContext() ctxt.beginScope() ctxt.setLocal('v1', 1) ctxt.setLocal('v2', 2) c = ctxt.vars self.assert_( c['v1'] == 1, 'Variable "v1"') ctxt.beginScope() ctxt.setLocal('v1', 3) ctxt.setGlobal('g', 1) c = ctxt.vars self.assert_( c['v1'] == 3, 'Inner scope') self.assert_( c['v2'] == 2, 'Outer scope') self.assert_( c['g'] == 1, 'Global') ctxt.endScope() c = ctxt.vars self.assert_( c['v1'] == 1, "Uncovered local") self.assert_( c['g'] == 1, "Global from inner scope") ctxt.endScope() class Harness(object): def __init__(self, testcase): self._callstack = [] self._testcase = testcase def _assert_(self, name, *args, **kwargs): self._callstack.append((name, args, kwargs)) def _complete_(self): self._testcase.assert_(len(self._callstack) == 0, "Harness methods called") def __getattr__(self, name): return HarnessMethod(self, name) class HarnessMethod(object): def __init__(self, harness, name): self._harness = harness self._name = name def __call__(self, *args, **kwargs): name = self._name self = self._harness cs = self._callstack self._testcase.assert_( len(cs), 'Unexpected harness method call "%s".' % name ) self._testcase.assert_( cs[0][0] == name, 'Harness method name "%s" called, "%s" expected.' % (name, cs[0][0]) ) name, aargs, akwargs = self._callstack.pop(0) self._testcase.assert_(aargs == args, "Harness method arguments") self._testcase.assert_(akwargs == kwargs, "Harness method keyword args") def test_suite(): checker = renormalizing.RENormalizing([ (re.compile(r"object of type 'MyIter' has no len\(\)"), r"len() of unsized object"), ]) suite = unittest.makeSuite(TALESTests) suite.addTest(DocTestSuite("zope.tales.tales",checker=checker)) return suite if __name__ == '__main__': unittest.TextTestRunner().run(test_suite()) zope.tales-3.5.3/src/zope/tales/tests/simpleexpr.py0000664000177100020040000000207612060151463023517 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Simple TALES Expression $Id: simpleexpr.py 126816 2012-06-11 19:00:21Z tseaver $ """ class SimpleExpr(object): '''Simple example of an expression type handler for testing ''' def __init__(self, name, expr, engine): self._name = name self._expr = expr def __call__(self, econtext): return self._name, self._expr def __repr__(self): return '' % (self._name, `self._expr`) zope.tales-3.5.3/src/zope/tales/tests/__init__.py0000664000177100020040000000007512060151463023063 0ustar menesismenesis00000000000000# # This file is necessary to make this directory a package. zope.tales-3.5.3/src/zope/tales/tests/test_expressions.py0000664000177100020040000003170112060151463024745 0ustar menesismenesis00000000000000# -*- coding: utf-8 -*- ############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Default TALES expression implementations tests. $Id: test_expressions.py 126816 2012-06-11 19:00:21Z tseaver $ """ import unittest from zope.tales.engine import Engine from zope.tales.interfaces import ITALESFunctionNamespace from zope.tales.tales import Undefined from zope.interface import implements class Data(object): def __init__(self, **kw): self.__dict__.update(kw) def __repr__(self): return self.name __str__ = __repr__ class ErrorGenerator: def __getitem__(self, name): import __builtin__ if name == 'Undefined': e = Undefined else: e = getattr(__builtin__, name, None) if e is None: e = SystemError raise e('mess') class ExpressionTestBase(unittest.TestCase): def setUp(self): # Test expression compilation d = Data( name = 'xander', y = Data( name = 'yikes', z = Data(name = 'zope') ) ) at = Data( name = 'yikes', _d = d ) self.context = Data( vars = dict( x = d, y = Data(z = 3), b = 'boot', B = 2, adapterTest = at, dynamic = 'z', eightBits = 'déjà vu', ErrorGenerator = ErrorGenerator(), ) ) self.engine = Engine class ExpressionTests(ExpressionTestBase): def testSimple(self): expr = self.engine.compile('x') context=self.context self.assertEqual(expr(context), context.vars['x']) def testPath(self): expr = self.engine.compile('x/y') context=self.context self.assertEqual(expr(context), context.vars['x'].y) def testLongPath(self): expr = self.engine.compile('x/y/z') context=self.context self.assertEqual(expr(context), context.vars['x'].y.z) def testOrPath(self): expr = self.engine.compile('path:a|b|c/d/e') context=self.context self.assertEqual(expr(context), 'boot') for e in 'Undefined', 'AttributeError', 'LookupError', 'TypeError': expr = self.engine.compile('path:ErrorGenerator/%s|b|c/d/e' % e) context=self.context self.assertEqual(expr(context), 'boot') def testDynamic(self): expr = self.engine.compile('x/y/?dynamic') context=self.context self.assertEqual(expr(context),context.vars['x'].y.z) def testBadInitalDynamic(self): from zope.tales.tales import CompilerError try: self.engine.compile('?x') except CompilerError,e: self.assertEqual(e.args[0], 'Dynamic name specified in first subpath element') else: self.fail('Engine accepted first subpath element as dynamic') def testOldStyleClassIsCalled(self): class AnOldStyleClass: pass self.context.vars['oldstyleclass'] = AnOldStyleClass expr = self.engine.compile('oldstyleclass') self.assert_(isinstance(expr(self.context), AnOldStyleClass)) def testString(self): expr = self.engine.compile('string:Fred') context=self.context result = expr(context) self.assertEqual(result, 'Fred') self.failUnless(isinstance(result, str)) def testStringSub(self): expr = self.engine.compile('string:A$B') context=self.context self.assertEqual(expr(context), 'A2') def testStringSub_w_python(self): CompilerError = self.engine.getCompilerError() self.assertRaises(CompilerError, self.engine.compile, 'string:${python:1}') def testStringSubComplex(self): expr = self.engine.compile('string:a ${x/y} b ${y/z} c') context=self.context self.assertEqual(expr(context), 'a yikes b 3 c') def testStringSubComplex_w_miss_and_python(self): # See https://bugs.launchpad.net/zope.tales/+bug/1002242 CompilerError = self.engine.getCompilerError() self.assertRaises(CompilerError, self.engine.compile, 'string:${nothig/nothing|python:1}') def testString8Bits(self): # Simple eight bit string interpolation should just work. expr = self.engine.compile('string:a ${eightBits}') context=self.context self.assertEqual(expr(context), 'a déjà vu') def testStringUnicode(self): # Unicode string expressions should return unicode strings expr = self.engine.compile(u'string:Fred') context=self.context result = expr(context) self.assertEqual(result, u'Fred') self.failUnless(isinstance(result, unicode)) def testStringFailureWhenMixed(self): # Mixed Unicode and 8bit string interpolation fails with a # UnicodeDecodeError, assuming there is no default encoding expr = self.engine.compile(u'string:a ${eightBits}') self.assertRaises(UnicodeDecodeError, expr, self.context) def testPython(self): expr = self.engine.compile('python: 2 + 2') context=self.context self.assertEqual(expr(context), 4) def testPythonCallableIsntCalled(self): self.context.vars['acallable'] = lambda: 23 expr = self.engine.compile('python: acallable') self.assertEqual(expr(self.context), self.context.vars['acallable']) def testPythonNewline(self): expr = self.engine.compile('python: 2 \n+\n 2\n') context=self.context self.assertEqual(expr(context), 4) def testPythonDosNewline(self): expr = self.engine.compile('python: 2 \r\n+\r\n 2\r\n') context=self.context self.assertEqual(expr(context), 4) def testPythonErrorRaisesCompilerError(self): self.assertRaises(self.engine.getCompilerError(), self.engine.compile, 'python: splat.0') def testHybridPathExpressions(self): def eval(expr): e = self.engine.compile(expr) return e(self.context) self.context.vars['one'] = 1 self.context.vars['acallable'] = lambda: 23 self.assertEqual(eval('foo | python:1+1'), 2) self.assertEqual(eval('foo | python:acallable'), self.context.vars['acallable']) self.assertEqual(eval('foo | string:x'), 'x') self.assertEqual(eval('foo | string:$one'), '1') self.assert_(eval('foo | exists:x')) def testEmptyPathSegmentRaisesCompilerError(self): CompilerError = self.engine.getCompilerError() def check(expr): self.assertRaises(CompilerError, self.engine.compile, expr) # path expressions on their own: check('/ab/cd | c/d | e/f') check('ab//cd | c/d | e/f') check('ab/cd/ | c/d | e/f') check('ab/cd | /c/d | e/f') check('ab/cd | c//d | e/f') check('ab/cd | c/d/ | e/f') check('ab/cd | c/d | /e/f') check('ab/cd | c/d | e//f') check('ab/cd | c/d | e/f/') # path expressions embedded in string: expressions: check('string:${/ab/cd}') check('string:${ab//cd}') check('string:${ab/cd/}') check('string:foo${/ab/cd | c/d | e/f}bar') check('string:foo${ab//cd | c/d | e/f}bar') check('string:foo${ab/cd/ | c/d | e/f}bar') check('string:foo${ab/cd | /c/d | e/f}bar') check('string:foo${ab/cd | c//d | e/f}bar') check('string:foo${ab/cd | c/d/ | e/f}bar') check('string:foo${ab/cd | c/d | /e/f}bar') check('string:foo${ab/cd | c/d | e//f}bar') check('string:foo${ab/cd | c/d | e/f/}bar') def test_defer_expression_returns_wrapper(self): from zope.tales.expressions import DeferWrapper expr = self.engine.compile('defer: b') context=self.context self.failUnless(isinstance(expr(context), DeferWrapper)) def test_lazy_expression_returns_wrapper(self): from zope.tales.expressions import LazyWrapper expr = self.engine.compile('lazy: b') context=self.context self.failUnless(isinstance(expr(context), LazyWrapper)) class FunctionTests(ExpressionTestBase): def setUp(self): ExpressionTestBase.setUp(self) # a test namespace class TestNameSpace(object): implements(ITALESFunctionNamespace) def __init__(self, context): self.context = context def setEngine(self, engine): self._engine = engine def engine(self): return self._engine def upper(self): return str(self.context).upper() def __getitem__(self,key): if key=='jump': return self.context._d raise KeyError,key self.TestNameSpace = TestNameSpace self.engine.registerFunctionNamespace('namespace', self.TestNameSpace) ## framework-ish tests def testSetEngine(self): expr = self.engine.compile('adapterTest/namespace:engine') self.assertEqual(expr(self.context), self.context) def testGetFunctionNamespace(self): self.assertEqual( self.engine.getFunctionNamespace('namespace'), self.TestNameSpace ) def testGetFunctionNamespaceBadNamespace(self): self.assertRaises(KeyError, self.engine.getFunctionNamespace, 'badnamespace') ## compile time tests def testBadNamespace(self): # namespace doesn't exist from zope.tales.tales import CompilerError try: self.engine.compile('adapterTest/badnamespace:title') except CompilerError,e: self.assertEqual(e.args[0],'Unknown namespace "badnamespace"') else: self.fail('Engine accepted unknown namespace') def testBadInitialNamespace(self): # first segment in a path must not have modifier from zope.tales.tales import CompilerError self.assertRaises(CompilerError, self.engine.compile, 'namespace:title') # In an ideal world there would be another test here to test # that a nicer error was raised when you tried to use # something like: # standard:namespace:upper # ...as a path. # However, the compilation stage of PathExpr currently # allows any expression type to be nested, so something like: # standard:standard:context/attribute # ...will work fine. # When that is changed so that only expression types which # should be nested are nestable, then the additional test # should be added here. def testInvalidNamespaceName(self): from zope.tales.tales import CompilerError try: self.engine.compile('adapterTest/1foo:bar') except CompilerError,e: self.assertEqual(e.args[0], 'Invalid namespace name "1foo"') else: self.fail('Engine accepted invalid namespace name') def testBadFunction(self): # namespace is fine, adapter is not defined try: expr = self.engine.compile('adapterTest/namespace:title') expr(self.context) except KeyError,e: self.assertEquals(e.args[0],'title') else: self.fail('Engine accepted unknown function') ## runtime tests def testNormalFunction(self): expr = self.engine.compile('adapterTest/namespace:upper') self.assertEqual(expr(self.context), 'YIKES') def testFunctionOnFunction(self): expr = self.engine.compile('adapterTest/namespace:jump/namespace:upper') self.assertEqual(expr(self.context), 'XANDER') def testPathOnFunction(self): expr = self.engine.compile('adapterTest/namespace:jump/y/z') context = self.context self.assertEqual(expr(context), context.vars['x'].y.z) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(ExpressionTests), unittest.makeSuite(FunctionTests), )) if __name__ == '__main__': unittest.TextTestRunner().run(test_suite()) zope.tales-3.5.3/src/zope/tales/engine.py0000664000177100020040000000302312060151463021423 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Expression engine configuration and registration. Each expression engine can have its own expression types and base names. $Id: engine.py 126816 2012-06-11 19:00:21Z tseaver $ """ from zope.tales.tales import ExpressionEngine from zope.tales.expressions import PathExpr from zope.tales.expressions import StringExpr from zope.tales.expressions import NotExpr from zope.tales.expressions import DeferExpr from zope.tales.expressions import LazyExpr from zope.tales.expressions import SimpleModuleImporter from zope.tales.pythonexpr import PythonExpr def Engine(): e = ExpressionEngine() reg = e.registerType for pt in PathExpr._default_type_names: reg(pt, PathExpr) reg('string', StringExpr) reg('python', PythonExpr) reg('not', NotExpr) reg('defer', DeferExpr) reg('lazy', LazyExpr) e.registerBaseName('modules', SimpleModuleImporter()) return e Engine = Engine() zope.tales-3.5.3/src/zope/__init__.py0000664000177100020040000000007012060151463020604 0ustar menesismenesis00000000000000__import__('pkg_resources').declare_namespace(__name__) zope.tales-3.5.3/src/zope.tales.egg-info/0000775000177100020040000000000012060151477021304 5ustar menesismenesis00000000000000zope.tales-3.5.3/src/zope.tales.egg-info/namespace_packages.txt0000664000177100020040000000000512060151473025626 0ustar menesismenesis00000000000000zope zope.tales-3.5.3/src/zope.tales.egg-info/not-zip-safe0000664000177100020040000000000112060151464023526 0ustar menesismenesis00000000000000 zope.tales-3.5.3/src/zope.tales.egg-info/requires.txt0000664000177100020040000000006712060151473023703 0ustar menesismenesis00000000000000setuptools zope.interface zope.tal [test] zope.testingzope.tales-3.5.3/src/zope.tales.egg-info/dependency_links.txt0000664000177100020040000000000112060151473025346 0ustar menesismenesis00000000000000 zope.tales-3.5.3/src/zope.tales.egg-info/SOURCES.txt0000664000177100020040000000132412060151474023165 0ustar menesismenesis00000000000000CHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt bootstrap.py buildout.cfg setup.py src/zope/__init__.py src/zope.tales.egg-info/PKG-INFO src/zope.tales.egg-info/SOURCES.txt src/zope.tales.egg-info/dependency_links.txt src/zope.tales.egg-info/namespace_packages.txt src/zope.tales.egg-info/not-zip-safe src/zope.tales.egg-info/requires.txt src/zope.tales.egg-info/top_level.txt src/zope/tales/__init__.py src/zope/tales/engine.py src/zope/tales/expressions.py src/zope/tales/interfaces.py src/zope/tales/pythonexpr.py src/zope/tales/tales.py src/zope/tales/tests/__init__.py src/zope/tales/tests/simpleexpr.py src/zope/tales/tests/test_expressions.py src/zope/tales/tests/test_tales.py src/zope/tales/tests/test_traverser.pyzope.tales-3.5.3/src/zope.tales.egg-info/PKG-INFO0000664000177100020040000000425512060151473022403 0ustar menesismenesis00000000000000Metadata-Version: 1.1 Name: zope.tales Version: 3.5.3 Summary: Zope Template Application Language Expression Syntax (TALES) Home-page: http://pypi.python.org/pypi/zope.tales Author: Zope Corporation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: Overview ======== Template Attribute Language - Expression Syntax See http://wiki.zope.org/ZPT/TALESSpecification13 CHANGES ======= 3.5.3 (2012-12-06) ------------------ - Fixed URL for TALES 1.3 spec in README. https://bugs.launchpad.net/bugs/1004025 3.5.2 (2012-05-23) ------------------ - Subexpressions of a 'string:' expression can be only path expressions. https://bugs.launchpad.net/zope.tales/+bug/1002242 3.5.1 (2010-04-30) ------------------ - Removed use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest. 3.5.0 (2010-01-01) ------------------ - Ported the lazy expression from Products.PageTemplates. 3.4.0 (2007-10-03) ------------------ - Updated package setup. - Initial release outside the Zope 3 trunk. 3.2.0 (2006-01-05) ------------------ - Corresponds to the verison of the zope.tales package shipped as part of the Zope 3.2.0 release. - Documentation / test fixes. 3.0.0 (2004-11-07) ------------------ - Corresponds to the verison of the zope.tales package shipped as part of the Zope X3.0.0 release. Keywords: zope template xml tales Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.tales-3.5.3/src/zope.tales.egg-info/top_level.txt0000664000177100020040000000000512060151473024025 0ustar menesismenesis00000000000000zope zope.tales-3.5.3/buildout.cfg0000664000177100020040000000013412060151463017240 0ustar menesismenesis00000000000000[buildout] develop = . parts = test [test] recipe = zc.recipe.testrunner eggs = zope.tales zope.tales-3.5.3/COPYRIGHT.txt0000664000177100020040000000004012060151463017035 0ustar menesismenesis00000000000000Zope Foundation and Contributorszope.tales-3.5.3/setup.py0000664000177100020040000000464212060151463016452 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2007 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## # This package is developed by the Zope Toolkit project, documented here: # http://docs.zope.org/zopetoolkit # When developing and releasing this package, please follow the documented # Zope Toolkit policies as described by this documentation. ############################################################################## """Setup for zope.tales package $Id: setup.py 128536 2012-12-06 17:16:18Z menesis $ """ import os from setuptools import setup, find_packages def read(*rnames): return open(os.path.join(os.path.dirname(__file__), *rnames)).read() setup(name='zope.tales', version='3.5.3', author='Zope Corporation and Contributors', author_email='zope-dev@zope.org', description='Zope Template Application Language Expression Syntax ' '(TALES)', long_description=( read('README.txt') + '\n\n' + read('CHANGES.txt') ), keywords = "zope template xml tales", classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', 'Framework :: Zope3'], url='http://pypi.python.org/pypi/zope.tales', license='ZPL 2.1', packages=find_packages('src'), package_dir = {'': 'src'}, namespace_packages=['zope'], extras_require = dict( test=['zope.testing', ]), install_requires=[ 'setuptools', 'zope.interface', 'zope.tal'], include_package_data = True, zip_safe = False, ) zope.tales-3.5.3/PKG-INFO0000664000177100020040000000425512060151477016042 0ustar menesismenesis00000000000000Metadata-Version: 1.1 Name: zope.tales Version: 3.5.3 Summary: Zope Template Application Language Expression Syntax (TALES) Home-page: http://pypi.python.org/pypi/zope.tales Author: Zope Corporation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: Overview ======== Template Attribute Language - Expression Syntax See http://wiki.zope.org/ZPT/TALESSpecification13 CHANGES ======= 3.5.3 (2012-12-06) ------------------ - Fixed URL for TALES 1.3 spec in README. https://bugs.launchpad.net/bugs/1004025 3.5.2 (2012-05-23) ------------------ - Subexpressions of a 'string:' expression can be only path expressions. https://bugs.launchpad.net/zope.tales/+bug/1002242 3.5.1 (2010-04-30) ------------------ - Removed use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest. 3.5.0 (2010-01-01) ------------------ - Ported the lazy expression from Products.PageTemplates. 3.4.0 (2007-10-03) ------------------ - Updated package setup. - Initial release outside the Zope 3 trunk. 3.2.0 (2006-01-05) ------------------ - Corresponds to the verison of the zope.tales package shipped as part of the Zope 3.2.0 release. - Documentation / test fixes. 3.0.0 (2004-11-07) ------------------ - Corresponds to the verison of the zope.tales package shipped as part of the Zope X3.0.0 release. Keywords: zope template xml tales Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.tales-3.5.3/bootstrap.py0000664000177100020040000000742212060151463017326 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (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. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. $Id: bootstrap.py 111793 2010-04-30 22:15:26Z hannosch $ """ import os, shutil, sys, tempfile, urllib2 from optparse import OptionParser tmpeggs = tempfile.mkdtemp() is_jython = sys.platform.startswith('java') # parsing arguments parser = OptionParser() parser.add_option("-v", "--version", dest="version", help="use a specific zc.buildout version") parser.add_option("-d", "--distribute", action="store_true", dest="distribute", default=False, help="Use Disribute rather than Setuptools.") parser.add_option("-c", None, action="store", dest="config_file", help=("Specify the path to the buildout configuration " "file to be used.")) options, args = parser.parse_args() # if -c was provided, we push it back into args for buildout' main function if options.config_file is not None: args += ['-c', options.config_file] if options.version is not None: VERSION = '==%s' % options.version else: VERSION = '' USE_DISTRIBUTE = options.distribute args = args + ['bootstrap'] to_reload = False try: import pkg_resources if not hasattr(pkg_resources, '_distribute'): to_reload = True raise ImportError except ImportError: ez = {} if USE_DISTRIBUTE: exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py' ).read() in ez ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True) else: exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' ).read() in ez ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) if to_reload: reload(pkg_resources) else: import pkg_resources if sys.platform == 'win32': def quote(c): if ' ' in c: return '"%s"' % c # work around spawn lamosity on windows else: return c else: def quote (c): return c cmd = 'from setuptools.command.easy_install import main; main()' ws = pkg_resources.working_set if USE_DISTRIBUTE: requirement = 'distribute' else: requirement = 'setuptools' if is_jython: import subprocess assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd', quote(tmpeggs), 'zc.buildout' + VERSION], env=dict(os.environ, PYTHONPATH= ws.find(pkg_resources.Requirement.parse(requirement)).location ), ).wait() == 0 else: assert os.spawnle( os.P_WAIT, sys.executable, quote (sys.executable), '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION, dict(os.environ, PYTHONPATH= ws.find(pkg_resources.Requirement.parse(requirement)).location ), ) == 0 ws.add_entry(tmpeggs) ws.require('zc.buildout' + VERSION) import zc.buildout.buildout zc.buildout.buildout.main(args) shutil.rmtree(tmpeggs) zope.tales-3.5.3/setup.cfg0000664000177100020040000000007312060151477016560 0ustar menesismenesis00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zope.tales-3.5.3/CHANGES.txt0000664000177100020040000000165512060151463016552 0ustar menesismenesis00000000000000CHANGES ======= 3.5.3 (2012-12-06) ------------------ - Fixed URL for TALES 1.3 spec in README. https://bugs.launchpad.net/bugs/1004025 3.5.2 (2012-05-23) ------------------ - Subexpressions of a 'string:' expression can be only path expressions. https://bugs.launchpad.net/zope.tales/+bug/1002242 3.5.1 (2010-04-30) ------------------ - Removed use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest. 3.5.0 (2010-01-01) ------------------ - Ported the lazy expression from Products.PageTemplates. 3.4.0 (2007-10-03) ------------------ - Updated package setup. - Initial release outside the Zope 3 trunk. 3.2.0 (2006-01-05) ------------------ - Corresponds to the verison of the zope.tales package shipped as part of the Zope 3.2.0 release. - Documentation / test fixes. 3.0.0 (2004-11-07) ------------------ - Corresponds to the verison of the zope.tales package shipped as part of the Zope X3.0.0 release. zope.tales-3.5.3/LICENSE.txt0000664000177100020040000000402612060151463016557 0ustar menesismenesis00000000000000Zope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.