[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} ©
- </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