[Checkins] SVN: Sandbox/Chameleon/src/chameleon/core/ Removed expression language translation code; this will go in packages implementing concrete language subsets.

Malthe Borch mborch at gmail.com
Wed Sep 17 12:19:44 EDT 2008


Log message for revision 91208:
  Removed expression language translation code; this will go in packages implementing concrete language subsets.

Changed:
  U   Sandbox/Chameleon/src/chameleon/core/clauses.py
  U   Sandbox/Chameleon/src/chameleon/core/etree.py
  D   Sandbox/Chameleon/src/chameleon/core/expressions.py
  U   Sandbox/Chameleon/src/chameleon/core/generation.py
  U   Sandbox/Chameleon/src/chameleon/core/interfaces.py
  U   Sandbox/Chameleon/src/chameleon/core/testing.py
  U   Sandbox/Chameleon/src/chameleon/core/tests/test_doctests.py
  U   Sandbox/Chameleon/src/chameleon/core/tests/test_edgecases.py
  U   Sandbox/Chameleon/src/chameleon/core/tests/xinclude1.pt
  U   Sandbox/Chameleon/src/chameleon/core/translation.py
  U   Sandbox/Chameleon/src/chameleon/core/translation.txt
  U   Sandbox/Chameleon/src/chameleon/core/utils.py

-=-
Modified: Sandbox/Chameleon/src/chameleon/core/clauses.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/clauses.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/clauses.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -667,27 +667,25 @@
 
     def __init__(self, v, e, scope=(), repeatdict=True):
         self.variable = v
-        self.expression = e
+        #self.expression = e
         self.define = Define(v)
         self.assign = Assign(e)
         self.repeatdict = repeatdict
-
+        self.e = e
+        
     def begin(self, stream):
         variable = self.variable
 
-        if self.repeatdict:
-            # initialize variable scope
-            self.define.begin(stream)
+        # initialize variable scope
+        self.define.begin(stream)
 
-            # assign iterator
-            iterator = stream.save()
-            self.assign.begin(stream, iterator)
+        # assign iterator
+        iterator = stream.save()
+        self.assign.begin(stream, iterator)
 
-            # initialize iterator
+        if self.repeatdict:
             stream.write("%s = repeat.insert('%s', %s)" % (
                 iterator, variable, iterator))
-
-            # loop
             stream.write("try:")
             stream.indent()
             stream.write("%s = None" % variable)
@@ -695,15 +693,15 @@
             stream.write("while True:")
             stream.indent()
         else:
-            stream.write("for %s in %s:" % (variable, self.expression))
+            stream.write("for %s in %s:" % (variable, iterator))
             stream.indent()
 
     def end(self, stream):
         # cook before leaving loop
         stream.cook()
-
+        iterator = stream.restore()
+        
         if self.repeatdict:
-            iterator = stream.restore()
             stream.write("%s = %s.next()" % (self.variable, iterator))
             
         stream.out('\n')
@@ -716,8 +714,8 @@
             stream.write("pass")
             stream.outdent()
 
-            self.define.end(stream)
-            self.assign.end(stream)
+        self.assign.end(stream)
+        self.define.end(stream)
 
 class Write(object):
     """
@@ -736,7 +734,7 @@
     Try-except parts:
 
     >>> _out, _write, stream = testing.setup_stream()
-    >>> write = Write(testing.pyexp("undefined | 'New Delhi'"))
+    >>> write = Write(testing.pyexp('undefined', '"New Delhi"'))
     >>> write.begin(stream)
     >>> write.end(stream)
     >>> exec stream.getvalue()

Modified: Sandbox/Chameleon/src/chameleon/core/etree.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/etree.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/etree.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -3,15 +3,12 @@
 import utils
 import cgi
 import copy
+import base64
 import xml.parsers.expat
+
 from StringIO import StringIO
+from cPickle import dumps, loads
 
-class ValidationError(ValueError):
-    def __str__(self):
-        value, = self.args
-        return "Insertion of %s is not allowed." % \
-               repr(value)
-        
 def import_elementtree():
     try:
         import xml.etree.ElementTree as ET
@@ -28,13 +25,34 @@
         import_elementtree().fromstring("<div>%s</div>" % string)
     except xml.parsers.expat.ExpatError:
         raise ValidationError(string)
-        
+
+class ValidationError(ValueError):
+    def __str__(self):
+        value, = self.args
+        return "Insertion of %s is not allowed." % \
+               repr(value)
+
 class Parser(object):
     element_mapping = utils.emptydict()
-
+    
     def parse(self, body):
         return parse(body, self.element_mapping)
-        
+
+class Annotation(property):
+    def __init__(self, name, default=None):
+        property.__init__(self, self._get, self._set)
+        self.name = name
+        self.default = default
+
+    def _get(instance, element):
+        value = element.attrib.get(instance.name)
+        if value is not None:
+            return loads(base64.decodestring(value))
+        return instance.default
+
+    def _set(instance, element, value):
+        element.attrib[instance.name] = base64.encodestring(dumps(value))
+
 try:
     import lxml.etree
 
@@ -55,7 +73,7 @@
 
                 element = self.makeelement(
                     utils.xhtml_attr('cdata'))
-                element.attrib[utils.meta_attr('cdata')] = ""
+                element.meta_cdata = ""
                 element.text = cdata
                 element.tail = after
                 
@@ -69,7 +87,7 @@
 
                 element = self.makeelement(
                     utils.xhtml_attr('cdata'))
-                element.attrib[utils.meta_attr('cdata')] = ""
+                element.meta_cdata = ""
                 self.addnext(element)
 
                 element.text = cdata

Deleted: Sandbox/Chameleon/src/chameleon/core/expressions.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/expressions.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/expressions.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -1,645 +0,0 @@
-import zope.interface
-import zope.component
-
-import parser
-import re
-
-import interfaces
-import types
-import config
-import utils
-
-_marker = object()
-
-class ExpressionTranslation(object):
-    zope.interface.implements(interfaces.IExpressionTranslation)
-
-    re_pragma = re.compile(r'^\s*(?P<pragma>[a-z]+):')
-    re_interpolation = re.compile(r'(?P<prefix>[^\\]\$|^\$)({((?P<expression>.*)})?|(?P<variable>[A-Za-z][A-Za-z0-9_]*))')
-    re_method = re.compile(r'^(?P<name>[A-Za-z0-9_]+)'
-                           '(\((?P<args>[A-Za-z0-9_]+\s*(,\s*[A-Za-z0-9_]+)*)\))?')
-
-    def name(self, string):
-        return string
-    
-    def search(self, string):
-        """
-        We need to implement a ``validate``-method. Let's define that an
-        expression is valid if it contains an odd number of
-        characters.
-        
-          >>> class MockExpressionTranslation(ExpressionTranslation):
-          ...     def validate(self, string):
-          ...         if len(string) % 2 == 0: raise SyntaxError()
-
-          >>> search = MockExpressionTranslation().search
-          >>> search("a")
-          'a'
-          >>> search("ab")
-          'a'
-          >>> search("abc")
-          'abc'
-          
-        """
-
-        left = 0
-        right = left + 1
-
-        current = None
-
-        while right <= len(string):
-            expression = string[left:right]
-
-            try:
-                e = self.validate(expression)
-                current = expression
-            except SyntaxError, e:
-                if right == len(string):
-                    if current is not None:
-                        return current
-
-                    raise e
-
-            right += 1
-
-        return current
-
-    def declaration(self, string):
-        """
-          >>> declaration = ExpressionTranslation().declaration
-
-        Single variable:
-
-          >>> declaration("variable")
-          declaration('variable')
-
-        Multiple variables:
-
-          >>> declaration("variable1, variable2")
-          declaration('variable1', 'variable2')
-
-        Repeat not allowed:
-
-          >>> declaration('repeat')
-          Traceback (most recent call last):
-          ...
-          ValueError: Invalid variable name 'repeat' (reserved).
-
-          >>> declaration('_disallowed')
-          Traceback (most recent call last):
-          ...
-          ValueError: Invalid variable name '_disallowed' (starts with an underscore).
-        """
-
-        variables = []
-        for var in string.split(', '):
-            var = var.strip()
-
-            if var in ('repeat',):
-                raise ValueError, "Invalid variable name '%s' (reserved)." % var
-
-            if var.startswith('_') and not var.startswith('_tmp'):
-                raise ValueError(
-                    "Invalid variable name '%s' (starts with an underscore)." % var)
-
-            variables.append(var)
-
-        return types.declaration(variables)
-
-    def mapping(self, string):
-        """
-          >>> mapping = ExpressionTranslation().mapping
-          
-          >>> mapping("abc def")
-          mapping(('abc', 'def'),)
-
-          >>> mapping("abc def;")
-          mapping(('abc', 'def'),)
-
-          >>> mapping("abc")
-          mapping(('abc', None),)
-
-          >>> mapping("abc;")
-          mapping(('abc', None),)
-
-          >>> mapping("abc; def ghi")
-          mapping(('abc', None), ('def', 'ghi'))
-
-        """
-
-        defs = string.split(';')
-        mappings = []
-        for d in defs:
-            d = d.strip()
-            if d == '':
-                continue
-
-            while '  ' in d:
-                d = d.replace('  ', ' ')
-
-            parts = d.split(' ')
-            if len(parts) == 1:
-                mappings.append((d, None))
-            elif len(parts) == 2:
-                mappings.append((parts[0], parts[1]))
-            else:
-                raise ValueError, "Invalid mapping (%s)." % string
-
-        return types.mapping(mappings)
-
-    def definitions(self, string):
-        """
-        
-        >>> class MockExpressionTranslation(ExpressionTranslation):
-        ...     def validate(self, string):
-        ...         if string == '' or ';' in string:
-        ...             raise SyntaxError()
-        ...
-        ...     def expression(self, string):
-        ...         self.validate(string)
-        ...         return types.value(string.strip())
-        
-        >>> definitions = MockExpressionTranslation().definitions
-        
-        Single define:
-        
-        >>> definitions("variable expression")
-        definitions((declaration('variable'), value('expression')),)
-        
-        Multiple defines:
-        
-        >>> definitions("variable1 expression1; variable2 expression2")
-        definitions((declaration('variable1'), value('expression1')),
-                    (declaration('variable2'), value('expression2')))
-        
-        Tuple define:
-        
-        >>> definitions("(variable1, variable2) (expression1, expression2)")
-        definitions((declaration('variable1', 'variable2'),
-                    value('(expression1, expression2)')),)
-
-        Global defines:
-
-        >>> definitions("global variable expression")
-        definitions((declaration('variable', global_scope=True), value('expression')),)
-
-        Space, the 'in' operator and '=' may be used to separate
-        variable from expression.
-
-        >>> definitions("variable in expression")
-        definitions((declaration('variable'), value('expression')),)        
-        
-        >>> definitions("variable1 = expression1; variable2 = expression2")
-        definitions((declaration('variable1'), value('expression1')),
-                    (declaration('variable2'), value('expression2')))
-
-        >>> definitions("variable1=expression1; variable2=expression2")
-        definitions((declaration('variable1'), value('expression1')),
-                    (declaration('variable2'), value('expression2')))
-        
-        A define clause that ends in a semicolon:
-        
-        >>> definitions("variable expression;")
-        definitions((declaration('variable'), value('expression')),)
-        
-        A define clause with a trivial expression (we do allow this):
-        
-        >>> definitions("variable")
-        definitions((declaration('variable'), None),)
-        
-        A proper define clause following one with a trivial expression:
-        
-        >>> definitions("variable1 expression; variable2")
-        definitions((declaration('variable1'), value('expression')),
-                    (declaration('variable2'), None))
-
-        """
-
-        string = string.replace('\n', '').strip()
-
-        defines = []
-        i = 0
-        while i < len(string):
-            global_scope = False
-            if string.startswith('global'):
-                global_scope = True
-                i += 6
-
-            while string[i] == ' ':
-                i += 1
-
-            # get variable definition
-            if string[i] == '(':
-                j = string.find(')', i+1)
-                if j == -1:
-                    raise ValueError, "Invalid variable tuple definition (%s)." % string
-                var = self.declaration(string[i+1:j])
-                j += 1
-            else:
-                j = string.find('=', i + 1)
-                k = string.find(' ', i + 1)
-                if k < j and k > -1 or j < 0:
-                    j = k
-                
-                if j < 0:
-                    var = self.declaration(string[i:])
-                    j = len(string)
-                else:
-                    var = self.declaration(string[i:j])
-
-            var.global_scope = global_scope
-            
-            # get expression
-            i = j + len(string) - j - len(string[j:].lstrip())
-
-            token = string[i:]
-            if token.startswith('=='):
-                raise ValueError("Invalid variable definition (%s)." % string)
-            elif token.startswith('='):
-                i += 1
-            elif token.startswith('in '):
-                i += 3
-
-            try:
-                expr = self.expression(string[i:])
-                j = -1
-            except SyntaxError, e:
-                expr = None
-                j = len(string)
-            
-            while j > i:
-                j = string.rfind(';', i, j)
-                if j < 0:
-                    raise e
-
-                try:
-                    expr = self.expression(string[i:j])
-                except SyntaxError, e:
-                    if string.rfind(';', i, j) > 0:
-                        continue
-                    raise e
-                
-                break
-                
-            defines.append((var, expr))
-
-            if j < 0:
-                break
-            
-            i = j + 1
-
-        return types.definitions(defines)
-
-    def definition(self, string):
-        defs = self.definitions(string)
-        if len(defs) != 1:
-            raise ValueError, "Multiple definitions not allowed."
-
-        return defs[0]
-
-    def output(self, string):
-        """
-        >>> class MockExpressionTranslation(ExpressionTranslation):
-        ...     def validate(self, string):
-        ...         return True
-        ...
-        ...     def translate(self, string):
-        ...         return types.value(string)
-
-        >>> output = MockExpressionTranslation().output
-
-        >>> output("context/title")
-        escape(value('context/title'),)
-
-        >>> output("context/pretty_title_or_id|context/title")
-        escape(value('context/pretty_title_or_id'), value('context/title'))
-
-        >>> output("structure context/title")
-        value('context/title')
-        
-        """
-        
-        if string.startswith('structure '):
-            return self.expression(string[len('structure'):])
-        
-        expression = self.expression(string)
-
-        if isinstance(expression, types.parts):
-            return types.escape(expression)
-
-        return types.escape((expression,))
-            
-    def expression(self, string):
-        """We need to implement the ``validate`` and
-        ``translate``-methods. Let's define that an expression is
-        valid if it contains an odd number of characters.
-        
-        >>> class MockExpressionTranslation(ExpressionTranslation):
-        ...     def validate(self, string):
-        ...         return True
-        ...
-        ...     def translate(self, string):
-        ...         return types.value(string)
-
-        >>> expression = MockExpressionTranslation().expression
-
-        >>> expression('a')
-        value('a')
-
-        >>> expression('a|b')
-        parts(value('a'), value('b'))
-    
-        """
-
-        string = string.replace('\n', '').strip()
-
-        if not string:
-            return types.parts()
-
-        parts = []
-
-        # default translator is ``self``
-        translator = self
-
-        i = j = 0
-        while i < len(string):
-            if translator is self:
-                match = self.re_pragma.match(string[i:])
-                if match is not None:
-                    pragma = match.group('pragma')
-
-                    translator = \
-                        zope.component.queryUtility(
-                            interfaces.IExpressionTranslation, name=pragma) or \
-                        zope.component.queryAdapter(
-                            self, interfaces.IExpressionTranslation, name=pragma)
-                    
-                    if translator is not None:
-                        i += match.end()
-                        continue
-
-                    translator = self
-
-            j = string.find('|', j + 1)
-            if j == -1:
-                j = len(string)
-
-            expr = string[i:j]
-
-            try:
-                translator.validate(expr)
-            except Exception, e:
-                if j < len(string):
-                    continue
-
-                # re-raise with traceback
-                translator.validate(expr)
-
-            value = translator.translate(expr)
-            parts.append(value)
-            translator = self
-            
-            i = j + 1
-
-        if len(parts) == 1:
-            return parts[0]
-
-        return types.parts(parts)
-
-    def interpolate(self, string):
-        """Search for an interpolation and return a match.
-
-        >>> class MockExpressionTranslation(ExpressionTranslation):
-        ...     def validate(self, string):
-        ...         if '}' in string: raise SyntaxError
-        ...
-        ...     def translate(self, string):
-        ...         return types.value(string)
-
-        >>> interpolate = MockExpressionTranslation().interpolate
-        
-        >>> interpolate('${abc}').group('expression')
-        'abc'
-
-        >>> interpolate(' ${abc}').group('expression')
-        'abc'
-
-        >>> interpolate('abc${def}').group('expression')
-        'def'
-
-        >>> interpolate('abc${def}ghi${jkl}').group('expression')
-        'def'
-
-        >>> interpolate('$abc').group('variable')
-        'abc'
-
-        >>> interpolate('${abc')
-        Traceback (most recent call last):
-          ...
-        SyntaxError: Interpolation expressions must be of the form ${<expression>} (${abc)
-        
-        """
-
-        m = self.re_interpolation.search(string)
-        if m is None:
-            return None
-
-        expression = m.group('expression')
-        variable = m.group('variable')
-        
-        if expression:
-            left = m.start()+len(m.group('prefix'))+1
-            right = string.find('}')
-
-            while right != -1:
-                match = string[left:right]
-                try:
-                    exp = self.expression(match)
-                    break
-                except SyntaxError:
-                    right = string.find('}', right)
-            else:
-                raise
-
-            string = string[:right+1]
-            return self.re_interpolation.search(string)
-
-        if m is None or (expression is None and variable is None):
-            raise SyntaxError(
-                "Interpolation expressions must be of the "
-                "form ${<expression>} (%s)" % string)
-
-        if expression and not m.group('expression'):
-            raise SyntaxError(expression)
-
-        return m
-
-    def method(self, string):
-        """Parse a method definition.
-
-        >>> method = ExpressionTranslation().method
-
-        >>> method('name')
-        name()
-
-        >>> method('name(a, b, c)')
-        name(a, b, c)
-        
-        """
-
-        m = self.re_method.match(string)
-        if m is None:
-            raise ValueError("Not a valid method definition (%s)." % string)
-
-        name = m.group('name')
-        args = [arg.strip() for arg in (m.group('args') or "").split(',') if arg]
-
-        return types.method(name, args)
-        
-class PythonTranslation(ExpressionTranslation):
-    def validate(self, string):
-        """We use the ``parser`` module to determine if
-        an expression is a valid python expression."""
-
-        if isinstance(string, unicode):
-            string = string.encode('utf-8')
-            
-        parser.expr(string.strip())
-
-    def translate(self, string):
-        if isinstance(string, str):
-            string = string.decode('utf-8')
-
-        return types.value(string.strip())
-
-python_translation = PythonTranslation()
-
-class StringTranslation(ExpressionTranslation):
-    zope.component.adapts(interfaces.IExpressionTranslation)
-
-    def __init__(self, translator):
-        self.translator = translator
-
-    def validate(self, string):
-        self.interpolate(string)
-        self.split(string)
-            
-    def translate(self, string):
-        return types.join(self.split(string))
-            
-    def split(self, string):
-        """Split up an interpolation string expression into parts that
-        are either unicode strings or ``value``-tuples.
-
-        >>> class MockTranslation(ExpressionTranslation):
-        ...     def validate(self, string):
-        ...         if '}' in string: raise SyntaxError
-        ...
-        ...     def translate(self, string):
-        ...         return types.value(string)
-        
-        >>> class MockStringTranslation(StringTranslation):
-        ...     pass
-        
-        >>> split = MockStringTranslation(MockTranslation()).split
-
-        >>> split("${abc}")
-        (value('abc'),)
-
-        >>> split(" ${abc}")
-        (' ', value('abc'))
-
-        >>> split("abc${def}")
-        ('abc', value('def'))
-
-        >>> split("${def}abc")
-        (value('def'), 'abc')
-
-        >>> split("abc${def}ghi")
-        ('abc', value('def'), 'ghi')
-
-        >>> split("abc${def}ghi${jkl}")
-        ('abc', value('def'), 'ghi', value('jkl'))
-
-        >>> split("abc${def | ghi}")
-        ('abc', parts(value('def '), value(' ghi')))
-
-        >>> print split(u"abc${ghi}")
-        (u'abc', value('ghi'))
-        
-        """
-
-        m = self.translator.interpolate(string)
-        if m is None:
-            return (self._unescape(string),)
-
-        prefix = m.group('prefix')
-        parts = []
-        
-        start = m.start() + len(prefix) - 1
-        if start > 0:
-            text = string[:start]
-            parts.append(self._unescape(text))
-
-        expression = m.group('expression')
-        variable = m.group('variable')
-
-        if expression:
-            parts.append(self.translator.expression(expression))
-        elif variable:
-            parts.append(self.translator.expression(variable))
-                
-        rest = string[m.end():]
-        if len(rest):
-            parts.extend(self.split(rest))
-
-        return tuple(parts)
-
-    def definitions(self, string):
-        """
-        
-        >>> definitions = StringTranslation(python_translation).definitions
-        
-        Semi-colon literal.
-        
-        >>> definitions("variable part1;; part2")
-        definitions((declaration('variable'), join('part1; part2',)),)
-
-        >>> definitions("variable1 part1;; part2; variable2 part3")
-        definitions((declaration('variable1'), join('part1; part2',)),
-                    (declaration('variable2'), join('part3',)))
-    
-        """
-
-        return super(StringTranslation, self).definitions(string)
-
-    def _unescape(self, string):
-        """
-        >>> unescape = StringTranslation(python_translation)._unescape
-        
-        >>> unescape('string:Hello World')
-        'string:Hello World'
-        
-        >>> unescape('; string:Hello World')
-        Traceback (most recent call last):
-         ...
-        SyntaxError: Semi-colons in string-expressions must be escaped.
-
-        >>> unescape(';; string:Hello World')
-        '; string:Hello World'
-
-        >>> unescape('string:Hello World;')
-        'string:Hello World;'
-        
-        """
-        
-        i = string.rfind(';')
-        if i < 0 or i == len(string) - 1:
-            return string
-        
-        j = string.rfind(';'+';')
-        if j < 0 or i != j + 1:
-            raise SyntaxError(
-                "Semi-colons in string-expressions must be escaped.")
-        
-        return string.replace(';;', ';')

Modified: Sandbox/Chameleon/src/chameleon/core/generation.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/generation.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/generation.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -4,7 +4,6 @@
 
 import utils
 import etree
-import expressions
 
 template_wrapper = """\
 def render(%(init)s, %(args)s%(extra)s%(language)s=None):

Modified: Sandbox/Chameleon/src/chameleon/core/interfaces.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/interfaces.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/interfaces.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -1,59 +1,5 @@
 from zope import interface
 
-class IExpressionTranslation(interface.Interface):
-    """This interface defines an expression translation utility."""
-    
-    def name(string):
-        """Should interpret ``string`` as a name. This method will
-        usually be the identity function."""
-    
-    def value(string):
-        """Translate ``string`` to a value-expression tuple.
-
-        Specification:
-
-           value :: = expression [ |* value ]
-           expresion ::= an expression string
-
-           *) Using | as _logical or_ is not supported.
-
-        """
-
-    def validate(string):
-        """Raises exception if ``string`` is not a valid exception."""
-
-    def translate(string):
-        """Translates ``string``."""
-        
-    def search(string):
-        """Extracts the longest valid expression from the beginning of
-        the provided string."""
-
-    def variable(string):
-        """A variable definition.
-        
-        Specification:
-        
-           variables :: = variable_name [, variables]
-
-        """
-        
-    def mapping(string):
-        """A mapping definition."""
-
-    def definition(string):
-        """A definition."""
-
-    def definitions(string):
-        """Multiple definitions.
-        
-        Specification:
-
-           argument ::= define_var [';' define_var]
-           define_var ::= Name python_expression
-           
-        """
-
 class ITALIterator(interface.Interface):
     """A TAL iterator
 

Modified: Sandbox/Chameleon/src/chameleon/core/testing.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/testing.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/testing.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -1,24 +1,18 @@
 import translation
 import template
 import generation
-import expressions
 import doctypes
 import etree
 import config
 import utils
+import types
 
 from StringIO import StringIO
 from cPickle import dumps, loads
 
-class TestCompiler(translation.Compiler):
-    def __call__(self, *args, **kwargs):
-        template = translation.Compiler.__call__(self, *args, **kwargs)
-        template = loads(dumps(template))
-        return template
+def pyexp(*exps):
+    return types.parts([types.value(exp) for exp in exps])
 
-def pyexp(string):
-    return expressions.python_translation.expression(string)
-
 def setup_stream(encoding=None):
     class symbols(translation.Node.symbols):
         out = '_out'
@@ -44,12 +38,19 @@
     template = compiler(parameters=sorted(kwargs.keys()))
     return template.render(**kwargs)    
 
-class MockElement(translation.Element, translation.VariableInterpolation):
-    translator = expressions.python_translation
-    
-    def update(self):
-        translation.VariableInterpolation.update(self)
-        
+def compile_template(parser, body, **kwargs):
+    compiler = TestCompiler(
+        body, parser, implicit_doctype=doctypes.xhtml)
+    template = compiler(parameters=sorted(kwargs.keys()))
+    return template.render(**kwargs)    
+
+class TestCompiler(translation.Compiler):
+    def __call__(self, *args, **kwargs):
+        template = translation.Compiler.__call__(self, *args, **kwargs)
+        template = loads(dumps(template))
+        return template
+
+class MockElement(translation.Element):
     class node(translation.Node):
         def __getattr__(self, name):
             return None
@@ -78,7 +79,9 @@
 
         @property
         def include(self):
-            return self.element.xi_href
+            href = self.element.xi_href
+            if href is not None:
+                return types.value(repr(href))
 
         @property
         def format(self):
@@ -93,8 +96,7 @@
     pass
     
 class MockXiElement(MockElement):
-    xi_href = utils.attribute(
-        "href", lambda p: expressions.StringTranslation(p).expression)
+    xi_href = utils.attribute('href')
     xi_parse = utils.attribute("parse", default="xml")
 
 class MockParser(etree.Parser):

Modified: Sandbox/Chameleon/src/chameleon/core/tests/test_doctests.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/tests/test_doctests.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/tests/test_doctests.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -13,7 +13,7 @@
     
 def test_suite():
     filesuites = 'template.txt', 'codegen.txt', 'translation.txt'
-    testsuites = 'translation', 'clauses', 'expressions'
+    testsuites = 'translation', 'clauses'
 
     chameleon.core.config.DISK_CACHE = False
     

Modified: Sandbox/Chameleon/src/chameleon/core/tests/test_edgecases.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/tests/test_edgecases.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/tests/test_edgecases.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -2,35 +2,6 @@
 
 from zope.component.testing import PlacelessSetup
 
-class TestNumericEntityPlusUnicodeParameterInsertedLiterally(unittest.TestCase,
-                                                             PlacelessSetup):
-    # See also
-    # http://groups.google.com/group/z3c_pt/browse_thread/thread/aea963d25a1778d0?hl=en
-    def setUp(self):
-        PlacelessSetup.setUp(self)
-
-    def tearDown(self):
-        PlacelessSetup.tearDown(self)
-            
-    def test_it(self):
-        import chameleon.core
-        from chameleon.core.testing import MockTemplate
-        body = u"""\
-        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-        <html xmlns="http://www.w3.org/1999/xhtml">
-        ${foo} &#169;
-        </html>
-        """
-        expected = u"""\
-        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-        <html xmlns="http://www.w3.org/1999/xhtml">
-        foo \xa9
-        </html>"""
-        t = MockTemplate(body)
-        self.assertEqual(norm(t.render(foo=u'foo')), norm(expected))
-
 class TestExplicitDoctypes(unittest.TestCase, PlacelessSetup):
     def setUp(self):
         PlacelessSetup.setUp(self)

Modified: Sandbox/Chameleon/src/chameleon/core/tests/xinclude1.pt
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/tests/xinclude1.pt	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/tests/xinclude1.pt	2008-09-17 16:19:41 UTC (rev 91208)
@@ -1,4 +1,4 @@
 <div xmlns="http://www.w3.org/1999/xhtml"
      xmlns:xi="http://www.w3.org/2001/XInclude">
-  <xi:include href="xinclude${1+1}.pt" />
+  <xi:include href="xinclude2.pt" />
 </div>

Modified: Sandbox/Chameleon/src/chameleon/core/translation.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/translation.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/translation.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -1,7 +1,6 @@
 from StringIO import StringIO
 
 import generation
-import expressions
 import codegen
 import clauses
 import doctypes
@@ -344,7 +343,7 @@
         index = self.element.index(element)
 
         t = self.element.makeelement(utils.meta_attr('literal'))
-        t.attrib['omit-tag'] = ''
+        t.meta_omit = ""
         t.tail = element.tail
         t.text = unicode(element)
         for child in element.getchildren():
@@ -389,7 +388,7 @@
     providing a code stream object.
     """
 
-    translator = expressions.python_translation
+    translator = None
     
     class node(Node):
         @property
@@ -422,106 +421,27 @@
 
         raise ValueError("Can't locate stream object.")
 
-    meta_cdata = utils.attribute(
+    meta_cdata = etree.Annotation(
         utils.meta_attr('cdata'))
     
-    meta_omit = utils.attribute(
+    meta_omit = etree.Annotation(
         utils.meta_attr('omit-tag'))
+    
+    meta_attributes = etree.Annotation(
+        utils.meta_attr('attributes'))
 
-    meta_attributes =  utils.attribute(
-        utils.meta_attr('attributes'), lambda p: p.definitions)
+    meta_replace = etree.Annotation(
+        utils.meta_attr('replace'))
 
-    meta_replace = utils.attribute(
-        utils.meta_attr('replace'), lambda p: p.output)
-
 class MetaElement(Element):
-    meta_cdata = utils.attribute('cdata')
+    meta_cdata = etree.Annotation('cdata')
     
     meta_omit = True
-    
-    meta_attributes =  utils.attribute(
-        'attributes', lambda p: p.definitions)
-    meta_replace = utils.attribute(
-        'replace', lambda p: p.output)
 
-class NativeAttributePrefixSupport:
-    """Element mix-in which allows native attributes to appear with
-    namespace prefix.
+    meta_attributes = etree.Annotation('attributes')
 
-    >>> class MockElement(NativeAttributePrefixSupport):
-    ...     nsmap = {'prefix1': 'ns1'}
-    ...     prefix = 'prefix1'
-    ...     attrib = {'{ns1}attr1': '1', 'attr2': '2', '{ns2}attr3': '3'}
+    meta_replace = etree.Annotation('replace')
 
-    >>> element = MockElement()
-    >>> element.update()
-    >>> keys = utils.get_attributes_from_namespace(element, 'ns1').keys()
-    >>> tuple(sorted(keys))
-    ('attr1', 'attr2')
-    """
-    
-    def update(self):
-        namespace = self.nsmap[self.prefix]
-        for name, value in self.attrib.items():
-            if name.startswith('{%s}' % namespace):
-                del self.attrib[name]
-                name = name.split('}')[-1]
-                self.attrib[name] = value
-    
-class VariableInterpolation:
-    def update(self):
-        translator = self.translator
-        
-        if self.text is not None:
-            while self.text:
-                text = self.text
-                m = translator.interpolate(text)
-                if m is None:
-                    break
-
-                t = self.makeelement(utils.meta_attr('interpolation'))
-                expression = "structure " + \
-                             (m.group('expression') or m.group('variable'))
-                t.attrib['replace'] = expression
-                t.tail = text[m.end():]
-                self.insert(0, t)
-                t.update()
-
-                if m.start() == 0:
-                    self.text = text[2-len(m.group('prefix')):m.start()+1]
-                else:
-                    self.text = text[:m.start()+1]
-
-        if self.tail is not None:
-            while self.tail:
-                m = translator.interpolate(self.tail)
-                if m is None:
-                    break
-
-                t = self.makeelement(utils.meta_attr('interpolation'))
-                expression = "structure " + \
-                             (m.group('expression') or m.group('variable'))
-                t.attrib['replace'] = expression
-                t.tail = self.tail[m.end():]
-                parent = self.getparent()
-                parent.insert(parent.index(self)+1, t)
-                t.update()
-                                
-                self.tail = self.tail[:m.start()+len(m.group('prefix'))-1]
-
-        for name in utils.get_attributes_from_namespace(self, config.XHTML_NS):
-            value = self.attrib[name]
-
-            if translator.interpolate(value):
-                del self.attrib[name]
-
-                attributes = utils.meta_attr('attributes')
-                expr = '%s string:%s' % (name, value)
-                if attributes in self.attrib:
-                    self.attrib[attributes] += '; %s' % expr
-                else:
-                    self.attrib[attributes] = expr
-
 class Compiler(object):
     """Template compiler. ``implicit_doctype`` will be used as the
     document type if the template does not define one
@@ -586,7 +506,7 @@
             "<html xmlns='%s'></html>" % config.XHTML_NS, parser,
             implicit_doctype=None, encoding=kwargs.get('encoding'))
         compiler.root.text = body
-        compiler.root.attrib[utils.meta_attr('omit-tag')] = ""
+        compiler.root.meta_omit = ""
         return compiler
 
     def __call__(self, macro=None, global_scope=True, parameters=()):

Modified: Sandbox/Chameleon/src/chameleon/core/translation.txt
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/translation.txt	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/translation.txt	2008-09-17 16:19:41 UTC (rev 91208)
@@ -102,15 +102,29 @@
       Hello World!
     </html>
 
+:: HTML comments
+
+  >>> print render_xhtml("""\
+  ... <div xmlns="http://www.w3.org/1999/xhtml">
+  ...   <!-- a comment -->
+  ...   <!-- a multi-
+  ...        line comment -->
+  ... </div>""")
+  <div>
+    <!-- a comment -->
+    <!-- a multi-
+         line comment -->
+  </div>
+
 :: Literal comments (without embedded expressions) output literally
 
   >>> print render_xhtml("""\
   ... <html xmlns="http://www.w3.org/1999/xhtml">
   ...   <!-- hello world -->
   ... </html>""")
-    <html>
-      <!-- hello world -->
-    </html>
+  <html>
+    <!-- hello world -->
+  </html>
   
 Text templates
 --------------
@@ -121,7 +135,7 @@
   
   >>> css = """\
   ... #some-region {
-  ...    background: url(${'http://nohost/plone'}/logo.gif) no-repeat;
+  ...    background: url(http://nohost/plone/logo.gif) no-repeat;
   ... }"""
 
   >>> print render_text(css)
@@ -132,10 +146,10 @@
 A javascript document that prints out HTML:
 
   >>> js = """\
-  ... print '<div class="description">Hello ${'World!'}</div>';"""
+  ... print '<div class="description">Hello, world!</div>';"""
 
   >>> print render_text(js)
-  print '<div class="description">Hello World!</div>';
+  print '<div class="description">Hello, world!</div>';
 
 Ghosted templates
 -----------------

Modified: Sandbox/Chameleon/src/chameleon/core/utils.py
===================================================================
--- Sandbox/Chameleon/src/chameleon/core/utils.py	2008-09-17 10:56:56 UTC (rev 91207)
+++ Sandbox/Chameleon/src/chameleon/core/utils.py	2008-09-17 16:19:41 UTC (rev 91208)
@@ -1,4 +1,5 @@
 from zope import interface
+from zope import component
 
 import sys
 import config
@@ -38,21 +39,22 @@
         return g
     return decorate
 
-def attribute(ns, factory=None, default=None, encoding=None):
+def attribute(tokens, factory=None, default=None, encoding=None):
     def get(self):
-        value = self.attrib.get(ns)
-        if value is not None:
-            if encoding or self.stream.encoding:
-                value = value.encode(encoding or self.stream.encoding)
-            if factory is None:
-                return value
-            f = factory(self.translator)
-            return f(value)
-        elif default is not None:
+        for token in isinstance(tokens, tuple) and tokens or (tokens,):
+            value = self.attrib.get(token)
+            if value is not None:
+                if encoding or self.stream.encoding:
+                    value = value.encode(encoding or self.stream.encoding)
+                if factory is None:
+                    return value
+                f = factory(self.translator)
+                return f(value)
+
+        if default is not None:
             return default
-    def set(self, value):
-        self.attrib[ns] = value
-    return property(get, set)
+    
+    return property(get)
 
 def escape(string, quote=None, encoding=None):
     if not isinstance(string, unicode) and encoding:
@@ -77,9 +79,6 @@
         
     return string
 
-def identity(x):
-    return x
-
 class scope(list):
     def __init__(self, *args):
         global s_counter



More information about the Checkins mailing list