[Checkins] SVN: z3c.pt/ Initial import.
Malthe Borch
mborch at gmail.com
Mon Dec 3 10:00:50 EST 2007
Log message for revision 82096:
Initial import.
Changed:
A z3c.pt/
A z3c.pt/branches/
A z3c.pt/tags/
A z3c.pt/trunk/
A z3c.pt/trunk/README.txt
A z3c.pt/trunk/setup.py
A z3c.pt/trunk/z3c/
A z3c.pt/trunk/z3c/__init__.py
A z3c.pt/trunk/z3c/pt/
A z3c.pt/trunk/z3c/pt/BENCHMARKS.txt
A z3c.pt/trunk/z3c/pt/README.txt
A z3c.pt/trunk/z3c/pt/VERSION.txt
A z3c.pt/trunk/z3c/pt/__init__.py
A z3c.pt/trunk/z3c/pt/io.py
A z3c.pt/trunk/z3c/pt/pagetemplate.py
A z3c.pt/trunk/z3c/pt/tal.py
A z3c.pt/trunk/z3c/pt/tal.txt
A z3c.pt/trunk/z3c/pt/tests/
A z3c.pt/trunk/z3c/pt/tests/__init__.py
A z3c.pt/trunk/z3c/pt/tests/helloworld.pt
A z3c.pt/trunk/z3c/pt/tests/test_doctests.py
A z3c.pt/trunk/z3c/pt/translate.txt
-=-
Added: z3c.pt/trunk/README.txt
===================================================================
--- z3c.pt/trunk/README.txt (rev 0)
+++ z3c.pt/trunk/README.txt 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,13 @@
+Overview
+--------
+
+The z3c.pt package provides an alternative implementation of the TAL
+template language.
+
+In a nutshell:
+
+ - Templates are JIT-compiled
+ - Only python-expressions are supported
+ - Depends only on lxml
+
+The METAL macro language is not supported; i18n is on the to-do.
Added: z3c.pt/trunk/setup.py
===================================================================
--- z3c.pt/trunk/setup.py (rev 0)
+++ z3c.pt/trunk/setup.py 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,32 @@
+from setuptools import setup, find_packages
+import sys, os
+
+version = '0.1'
+
+setup(name='z3c.pt',
+ version=version,
+ description="An implementation of the TAL template language.",
+ long_description=open("README.txt").read(),
+ classifiers=[
+ "Programming Language :: Python",
+ "Topic :: Text Processing :: Markup :: HTML",
+ "Topic :: Text Processing :: Markup :: XML",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ ],
+ keywords='',
+ author='Malthe Borch',
+ author_email='mborch at gmail.com',
+ url='',
+ license='GPL',
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['z3c'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+ """,
+ )
Added: z3c.pt/trunk/z3c/__init__.py
===================================================================
--- z3c.pt/trunk/z3c/__init__.py (rev 0)
+++ z3c.pt/trunk/z3c/__init__.py 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: z3c.pt/trunk/z3c/pt/BENCHMARKS.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/BENCHMARKS.txt (rev 0)
+++ z3c.pt/trunk/z3c/pt/BENCHMARKS.txt 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,70 @@
+Benchmarks
+==========
+
+ zope.pagetemplate z3c.pt
+Hello World 4.482 1
+1000 x 10 table 4.540 1
+
+Source
+------
+
+ >>> from z3c.pt import PageTemplate
+ >>> from zope.pagetemplate.pagetemplate import PageTemplate as z3PageTemplate
+
+Hello World:
+
+ >>> template = PageTemplate("""\
+ ... <div xmlns="http://www.w3.org/1999/xhtml">
+ ... Hello World!
+ ... </div>""")
+
+ >>> # for i in range(300000): a = template()
+
+ >>> template = z3PageTemplate()
+ >>> template.pt_edit("""\
+ ... <div xmlns="http://www.w3.org/1999/xhtml">
+ ... Hello World!
+ ... </div>""", 'text/xhtml')
+
+ >>> # for i in range(300000): a = template()
+
+1000 x 10 table:
+
+ >>> table = [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) \
+ ... for x in range(1000)]
+
+ >>> template = PageTemplate("""\
+ ... <table xmlns="http://www.w3.org/1999/xhtml"
+ ... xmlns:tal="http://xml.zope.org/namespaces/tal">
+ ... <tr tal:repeat="row table">
+ ... <td tal:repeat="c row.values()"
+ ... tal:content="c" />
+ ... </tr>
+ ... </table>""")
+
+ >>> # for i in range(20): a = template(table=table)
+
+ >>> template = z3PageTemplate()
+ >>> template.pt_edit("""\
+ ... <table xmlns="http://www.w3.org/1999/xhtml"
+ ... xmlns:tal="http://xml.zope.org/namespaces/tal">
+ ... <tr tal:repeat="row options/table">
+ ... <td tal:repeat="c python: row.values()"
+ ... tal:content="c" />
+ ... </tr>
+ ... </table>""", 'text/xhtml')
+
+ >>> # for i in range(20): a = template(table=table)
+
+ >>> from StringIO import StringIO
+ >>> def bigtable(table):
+ ... out = StringIO()
+ ... for row in table:
+ ... out.write('<tr>')
+ ... for c in row.values():
+ ... out.write('<td>%s</td>' % c)
+ ... out.write('</tr>')
+ ... return out.getvalue()
+
+ >>> # for i in range(20): a = bigtable(table=table)
+
Added: z3c.pt/trunk/z3c/pt/README.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/README.txt (rev 0)
+++ z3c.pt/trunk/z3c/pt/README.txt 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,34 @@
+z3c.pt
+======
+
+Usage
+-----
+
+From a string:
+
+ >>> from z3c.pt import PageTemplate
+ >>> template = PageTemplate("""\
+ ... <div xmlns="http://www.w3.org/1999/xhtml"
+ ... xmlns:tal="http://xml.zope.org/namespaces/tal">
+ ... Hello World!
+ ... </div>
+ ... """)
+
+ >>> print template()
+ <div>
+ Hello World!
+ </div>
+
+From a file:
+
+ >>> from z3c.pt import PageTemplateFile
+ >>> from z3c.pt import tests
+ >>> filename = tests.__path__[0]+'/helloworld.pt'
+
+ >>> template = PageTemplateFile(filename)
+ >>> print template()
+ <div>
+ Hello World!
+ </div>
+
+Keyword-parameters are passed on to the template namespace as-is.
Added: z3c.pt/trunk/z3c/pt/VERSION.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/VERSION.txt (rev 0)
+++ z3c.pt/trunk/z3c/pt/VERSION.txt 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1 @@
+0.1
Added: z3c.pt/trunk/z3c/pt/__init__.py
===================================================================
--- z3c.pt/trunk/z3c/pt/__init__.py (rev 0)
+++ z3c.pt/trunk/z3c/pt/__init__.py 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,2 @@
+from pagetemplate import PageTemplate
+from pagetemplate import PageTemplateFile
Added: z3c.pt/trunk/z3c/pt/io.py
===================================================================
--- z3c.pt/trunk/z3c/pt/io.py (rev 0)
+++ z3c.pt/trunk/z3c/pt/io.py 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,58 @@
+from StringIO import StringIO
+
+class CodeIO(StringIO):
+ """
+ A high-level I/O class to write Python code to a stream.
+ Indentation is managed using ``indent`` and ``outdent``.
+
+ Convenience methods for keeping track of temporary
+ variables.
+
+ """
+
+ variable_prefix = '_saved'
+
+ def __init__(self, indentation_string="\t"):
+ StringIO.__init__(self)
+ self.indentation = 0
+ self.indentation_string = indentation_string
+ self.counter = 0
+ self.queue = u''
+
+ def save(self, variable=None):
+ self.counter += 1
+ if variable:
+ self.write("%s%d = %s" % (self.variable_prefix, self.counter, variable))
+ else:
+ return "%s%d" % (self.variable_prefix, self.counter)
+
+ def restore(self, variable=None):
+ if variable:
+ self.write("%s = %s%d" % (variable, self.variable_prefix, self.counter))
+ else:
+ return "%s%d" % (self.variable_prefix, self.counter)
+
+ self.counter -= 1
+
+ def indent(self, amount=1):
+ self.indentation += amount
+
+ def outdent(self, amount=1):
+ self.indentation -= amount
+
+ def out(self, string):
+ self.queue += string
+
+ def cook(self):
+ if self.queue:
+ queue = self.queue
+ self.queue = ''
+ self.write("_out.write('%s')" % queue)
+
+ def write(self, string):
+ self.cook()
+ StringIO.write(self, self.indentation_string * self.indentation + string + '\n')
+
+ def getvalue(self):
+ self.cook()
+ return StringIO.getvalue(self)
Added: z3c.pt/trunk/z3c/pt/pagetemplate.py
===================================================================
--- z3c.pt/trunk/z3c/pt/pagetemplate.py (rev 0)
+++ z3c.pt/trunk/z3c/pt/pagetemplate.py 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,108 @@
+import lxml.etree
+import StringIO
+
+import tal
+import io
+
+ns_lookup_table = [(f.__ns__, f) for f in (tal.define,
+ tal.condition,
+ tal.omit,
+ tal.repeat,
+ tal.attribute,
+ tal.replace,
+ tal.tag,
+ tal.content)]
+
+class PageTemplate(object):
+ def __init__(self, body):
+ self.body = body
+ self.render = None
+
+ def translate(self):
+ """Translates page template body to Python-code."""
+
+ tree = lxml.etree.parse(StringIO.StringIO(self.body))
+ root = tree.getroot()
+
+ stream = io.CodeIO(indentation_string=' ')
+
+ # imports and symbols
+ stream.write("from cgi import escape as _escape")
+ stream.write("from z3c.pt.tal import repeatdict as _repeatdict")
+ stream.write("from StringIO import StringIO as _StringIO")
+
+ stream.write("def render(**_kwargs):")
+ stream.indent()
+ stream.write("global _StringIO, _repeatdict, _escape")
+ stream.write("repeat = _repeatdict()")
+ stream.write("_attrs = {}")
+ stream.write("_scope = _kwargs.keys()")
+
+ # output
+ stream.write("_out = _StringIO()")
+
+ # set up keyword args
+ stream.write("for _variable, _value in _kwargs.items():")
+ stream.indent()
+ stream.write("globals()[_variable] = _value")
+ stream.outdent()
+
+ # translate tree
+ translate(root, stream)
+
+ # output
+ stream.write("return _out.getvalue()")
+ stream.outdent()
+
+ return stream.getvalue()
+
+ def cook(self):
+ exec self.translate()
+ self.render = render
+
+ @property
+ def template(self):
+ if self.render is None:
+ self.cook()
+
+ return self.render
+
+ def __call__(self, **kwargs):
+ return self.template(**kwargs)
+
+class PageTemplateFile(PageTemplate):
+ def __init__(self, filename):
+ self.filename = filename
+ self.render = None
+
+ @property
+ def body(self):
+ return open(self.filename, 'r').read()
+
+def translate(node, stream):
+ keys = node.keys() + [None]
+
+ handlers = [handler(node) for key, handler in ns_lookup_table \
+ if key in keys]
+
+ # remove namespace attributes
+ for key, handler in ns_lookup_table:
+ if key is not None and key in node.attrib:
+ del node.attrib[key]
+
+ # update node
+ for handler in handlers:
+ node = handler.update(node)
+
+ # begin tag
+ for handler in handlers:
+ handler.begin(stream)
+
+ # process children
+ if node:
+ for element in node:
+ translate(element, stream)
+
+ # end tag
+ for handler in reversed(handlers):
+ handler.end(stream)
Added: z3c.pt/trunk/z3c/pt/tal.py
===================================================================
--- z3c.pt/trunk/z3c/pt/tal.py (rev 0)
+++ z3c.pt/trunk/z3c/pt/tal.py 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,389 @@
+import parser
+import cgi
+import xml.sax.saxutils
+
+def expression(string):
+ """
+ Python-expressions in try-except construct.
+
+ Specification:
+
+ expression :: = python_expression [ |* expression ]
+ python_expresion ::= a python expression string
+
+ *) Using | as logical or is not supported.
+
+ """
+
+ string = string.replace('\n', '')
+
+ expression = []
+
+ i = j = 0
+ while i < len(string):
+ j = string.find('|', j + 1)
+ if j == -1:
+ j = len(string)
+
+ expr = string[i:j].lstrip()
+
+ try:
+ # we use the ``parser`` module to determine if
+ # an expression is a valid python expression
+ parser.expr(expr)
+ except SyntaxError, e:
+ if j < len(string):
+ continue
+
+ raise e
+
+ expression.append(expr)
+ i = j + 1
+
+ return expression
+
+def definition(string):
+ """
+ TAL define-expression:
+
+ Specification:
+
+ argument ::= define_var [';' define_var]
+ define_var ::= Name python_expression
+
+ """
+
+ string = string.replace('\n', '').strip()
+
+ defines = []
+
+ i = 0
+ while i < len(string):
+ while string[i] == ' ':
+ i += 1
+
+ # get variable name
+ j = string.find(' ', i + 1)
+ if j == -1:
+ raise ValueError, "Invalid define clause (%s)." % string
+
+ variable = string[i:j]
+
+ if variable in ('repeat',):
+ raise ValueError, "Invalid variable name '%s' (reserved)." % variable
+
+ if variable.startswith('_'):
+ raise ValueError, \
+ "Invalid variable name '%s' (starts with an underscore)." % variable
+ # get expression
+ i = j
+ while j < len(string):
+ j = string.find(';', j+1)
+ if j == -1:
+ j = len(string)
+
+ try:
+ expr = expression(string[i:j])
+ except SyntaxError, e:
+ continue
+ break
+ else:
+ raise e
+
+ defines.append((variable, expr))
+
+ i = j + 1
+
+ return defines
+
+class repeatitem(object):
+ def __init__(self, iterator, length):
+ self.length = length
+ self.iterator = iterator
+
+ @property
+ def index(self):
+ return self.length - len(self.iterator) - 1
+
+ @property
+ def start(self):
+ return self.index == 0
+
+ @property
+ def end(self):
+ return self.index == self.length - 1
+
+ def number(self):
+ return self.index + 1
+
+ def odd(self):
+ return bool(self.index % 2)
+
+ def even(self):
+ return not self.odd()
+
+class repeatdict(dict):
+ def __setitem__(self, key, iterator):
+ try:
+ length = len(iterator)
+ except TypeError:
+ length = None
+
+ dict.__setitem__(self, key, (iterator, length))
+
+ def __getitem__(self, key):
+ value, length = dict.__getitem__(self, key)
+
+ if not isinstance(value, repeatitem):
+ value = repeatitem(value, length)
+ self.__setitem__(key, value)
+
+ return value
+
+class Assign(object):
+ def __init__(self, expression):
+ self.expressions = expression
+
+ def begin(self, stream, variable):
+ """First n - 1 expressions must be try-except wrapped."""
+
+ for expression in self.expressions[:-1]:
+ stream.write("try:")
+ stream.indent()
+ stream.write("%s = %s" % (variable, expression))
+ stream.outdent()
+ stream.write("except Exception, e:")
+ stream.indent()
+
+ expression = self.expressions[-1]
+ stream.write("%s = %s" % (variable, expression))
+
+ def end(self, stream):
+ stream.outdent(len(self.expressions)-1)
+
+class Define(object):
+ def __init__(self, value):
+ self.defines = [(v, Assign(e)) for v, e in definition(value)]
+
+ def update(self, node):
+ return node
+
+ def begin(self, stream):
+ variables = [v for (v, e) in self.defines]
+
+ # save local variables already in scope
+ save = stream.save()
+ stream.write("%s = {}" % save)
+ for var in variables:
+ stream.write("if '%s' in _scope: %s['%s'] = %s" % (var, save, var, var))
+ stream.write("else: _scope.append('%s')" % var)
+
+ for variable, assign in self.defines:
+ assign.begin(stream, variable)
+ assign.end(stream)
+
+ def end(self, stream):
+ restore = stream.restore()
+
+ for variable, expression in reversed(self.defines):
+ # restore local variables previously in scope
+ stream.write("if '%s' in %s:" % (variable, restore))
+ stream.indent()
+ stream.write("%s = %s['%s']" % (variable, restore, variable))
+ stream.outdent()
+ stream.write("else:")
+ stream.indent()
+ stream.write("del %s" % variable)
+ stream.write("_scope.remove('%s')" % variable)
+ stream.outdent()
+
+class Condition(object):
+ def __init__(self, value):
+ self.assign = Assign(expression(value))
+
+ def update(self, node):
+ return node
+
+ def begin(self, stream):
+ variable = '_condition'
+
+ self.assign.begin(stream, variable)
+ stream.write("if %s:" % variable)
+ stream.indent()
+
+ def end(self, stream):
+ self.assign.end(stream)
+ stream.outdent()
+
+class Repeat(object):
+ def __init__(self, value):
+ string = value.lstrip().replace('\n', '')
+
+ space = string.find(' ')
+ if space == -1:
+ raise ValueError, "Invalid repeat clause (%s)." % value
+
+ self.variable = string[:space]
+ self.assign = Assign(expression(string[space:]))
+
+ def update(self, node):
+ return node
+
+ def begin(self, stream):
+ variable = self.variable
+ iterator = stream.save()
+
+ self.assign.begin(stream, iterator)
+
+ # define variable scope
+ self.define = Define("%s None" % self.variable)
+ self.define.begin(stream)
+
+ # initialize iterator
+ stream.write("repeat['%s'] = %s = %s.__iter__()" % (variable, iterator, iterator))
+
+ # loop
+ stream.write("while %s:" % iterator)
+ stream.indent()
+ stream.write("%s = %s.next()" % (variable, iterator))
+
+ def end(self, stream):
+ # cook before leaving loop
+ stream.cook()
+
+ stream.outdent()
+ self.define.end(stream)
+ self.assign.end(stream)
+ stream.restore()
+
+class Attribute(object):
+ def __init__(self, value):
+ self.attributes = definition(value)
+
+ def update(self, node):
+ for variable, expression in self.attributes:
+ if variable in node.attrib:
+ del node.attrib[variable]
+
+ return node
+
+ def begin(self, stream):
+ stream.write("_attrs = {}")
+ for variable, expression in self.attributes:
+ assign = Assign(expression)
+ assign.begin(stream, "_attrs['%s']" % variable)
+ assign.end(stream)
+
+ def end(self, stream):
+ pass
+
+class Content(object):
+ def __init__(self, value):
+ self.assign = Assign(expression(value))
+
+ def update(self, node):
+ node.text = ''
+ for element in node.getchildren():
+ node.remove(element)
+
+ return node
+
+ def begin(self, stream):
+ self.assign.begin(stream, '_content')
+ stream.write("_out.write(_content)")
+
+ def end(self, stream):
+ self.assign.end(stream)
+
+class Replace(Content):
+ def update(self, node):
+ return None
+
+class Tag(object):
+ def __init__(self, node):
+ self.node = node
+ self.tail = node.tail
+
+ @property
+ def tag(self):
+ tag = self.node.tag
+ if tag.startswith('{'):
+ return tag[tag.find('}')+1:]
+
+ return tag
+
+ def update(self, node):
+ self.node = node
+ return node
+
+ def begin(self, stream):
+ if self.node is None:
+ return
+ stream.out('<%s' % self.tag)
+ stream.write("for _name, _value in _attrs.items():")
+ stream.indent()
+ stream.write("""_out.write(' %s=\"%s\"' % (_name, _escape(_value, '\"')))""")
+ stream.outdent()
+ stream.write("_attrs.clear()")
+ for name, value in self.node.attrib.items():
+ stream.out(' %s=%s' % (name, xml.sax.saxutils.quoteattr(value)))
+
+ if self.node.text is None:
+ stream.out(' />')
+ else:
+ stream.out('>')
+
+ text = self.node.text
+ if text is not None:
+ text = cgi.escape(text.replace('\n', '\\n'), '"')
+ stream.out(text)
+
+ def end(self, stream):
+ if self.node is not None and self.node.text is not None:
+ stream.out('</%s>' % self.tag)
+
+ if self.tail is not None:
+ tail = cgi.escape(self.tail.replace('\n', '\\n'), "'")
+ stream.out(tail)
+
+def handler(key=None):
+ def decorate(f):
+ def g(node):
+ if key is None:
+ return f(node, None)
+ return f(node, node.get(key))
+ g.__ns__ = key
+ return g
+ return decorate
+
+ at handler("{http://xml.zope.org/namespaces/tal}define")
+def define(node, value):
+ return Define(value)
+
+ at handler("{http://xml.zope.org/namespaces/tal}condition")
+def condition(node, value):
+ return Condition(value)
+
+ at handler("{http://xml.zope.org/namespaces/tal}repeat")
+def repeat(node, value):
+ return Repeat(value)
+
+ at handler("{http://xml.zope.org/namespaces/tal}attributes")
+def attribute(node, value):
+ return Attribute(value)
+
+ at handler("{http://xml.zope.org/namespaces/tal}content")
+def content(node, value):
+ return Content(value)
+
+ at handler("{http://xml.zope.org/namespaces/tal}replace")
+def replace(node, value):
+ return Replace(value)
+
+ at handler("{http://xml.zope.org/namespaces/tal}omit-tag")
+def omit(node, value):
+ raise NotImplemented, "The tal:omit-tag statement is not supported yet."
+
+ at handler()
+def tag(node, value):
+ return Tag(node)
Added: z3c.pt/trunk/z3c/pt/tal.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/tal.txt (rev 0)
+++ z3c.pt/trunk/z3c/pt/tal.txt 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,226 @@
+TAL
+===
+
+Tests for the TAL language implementation.
+
+ >>> from z3c.pt import tal
+
+expression
+----------
+
+Simple expression:
+
+ >>> tal.expression("4 + 5")
+ ['4 + 5']
+
+Complex expressions:
+
+ >>> tal.expression("a.non_defined_method() | 1")
+ ['a.non_defined_method() ', '1']
+
+Expression with non-semantic horizontal bar.
+
+ >>> tal.expression("'|'")
+ ["'|'"]
+
+Expression with non-semantic horizontal bar and semantic bar.
+
+ >>> tal.expression("a.non_defined_method() | '|'")
+ ['a.non_defined_method() ', "'|'"]
+
+Define
+------
+
+ >>> from z3c.pt.io import CodeIO
+ >>> stream = CodeIO()
+ >>> _scope = []
+
+Variable scope:
+
+ >>> define = tal.Define("a b")
+ >>> b = object()
+ >>> define.begin(stream)
+ >>> exec stream.getvalue()
+ >>> a is b
+ True
+ >>> del a
+ >>> _scope.remove('a')
+ >>> define.end(stream)
+ >>> exec stream.getvalue()
+ >>> a
+ Traceback (most recent call last):
+ ...
+ NameError: name 'a' is not defined
+ >>> b is not None
+ True
+
+Multiple defines:
+
+ >>> define = tal.Define("a b; c d")
+ >>> d = object()
+ >>> define.begin(stream)
+ >>> exec stream.getvalue()
+ >>> a is b and c is d
+ True
+ >>> define.end(stream)
+ >>> del a; del c
+ >>> _scope.remove('a'); _scope.remove('c')
+ >>> exec stream.getvalue()
+ >>> a
+ Traceback (most recent call last):
+ ...
+ NameError: name 'a' is not defined
+ >>> c
+ Traceback (most recent call last):
+ ...
+ NameError: name 'c' is not defined
+ >>> b is not None and d is not None
+ True
+
+Using semicolons in expressions within a define:
+
+ >>> define = tal.Define("a ';'")
+ >>> define.begin(stream)
+ >>> exec stream.getvalue()
+ >>> a
+ ';'
+ >>> define.end(stream)
+
+Ending an define clause with a semicolon.
+
+ >>> define = tal.Define("a 4 + 5;")
+ >>> define.begin(stream)
+ >>> exec stream.getvalue()
+ >>> a
+ 9
+ >>> define.end(stream)
+
+Scope:
+
+ >>> a = 1
+ >>> define = tal.Define("a 2")
+ >>> define.begin(stream)
+ >>> define.end(stream)
+ >>> exec stream.getvalue()
+ >>> a
+ 1
+
+Conditions
+----------
+
+ >>> stream = CodeIO()
+
+True:
+
+ >>> a = 0
+ >>> condition = tal.Condition("True")
+ >>> define = tal.Define("a 1")
+ >>> condition.begin(stream)
+ >>> define.begin(stream)
+ >>> exec stream.getvalue()
+ >>> a
+ 1
+ >>> define.end(stream)
+ >>> condition.end(stream)
+
+False:
+
+ >>> a = 0
+ >>> condition = tal.Condition("False")
+ >>> define = tal.Define("a 1")
+ >>> condition.begin(stream)
+ >>> define.begin(stream)
+ >>> exec stream.getvalue()
+ >>> a
+ 0
+ >>> define.end(stream)
+ >>> condition.end(stream)
+
+Repeat
+------
+
+ >>> from z3c.pt.tal import repeatdict as _repeat
+ >>> repeat = _repeat()
+
+ >>> stream = CodeIO()
+
+ >>> _repeat = tal.Repeat("i range(5)")
+ >>> _repeat.begin(stream)
+ >>> stream.write("r = repeat['i']")
+ >>> stream.write("print (i, r.index, r.start, r.end, r.number(), r.odd(), r.even())")
+ >>> exec stream.getvalue()
+ (0, 0, True, False, 1, False, True)
+ (1, 1, False, False, 2, True, False)
+ (2, 2, False, False, 3, False, True)
+ (3, 3, False, False, 4, True, False)
+ (4, 4, False, True, 5, False, True)
+ >>> _repeat.end(stream)
+
+Attribute
+---------
+
+ >>> from z3c.pt.tal import Attribute
+ >>> stream = CodeIO()
+
+ >>> attribute = Attribute("class 'plain'")
+ >>> attribute.begin(stream)
+ >>> attribute.end(stream)
+ >>> exec stream.getvalue()
+ >>> _attrs
+ {'class': 'plain'}
+ >>> del _attrs
+
+Attributes that are bound to expressions will be removed on ``update``:
+
+ >>> from lxml.etree import Element
+ >>> img = Element('img')
+ >>> img.set('src', u'logo.gif')
+ >>> img.set('class', u'stx')
+ >>> img = attribute.update(img)
+ >>> img.attrib
+ {'src': 'logo.gif'}
+
+Content
+-------
+
+ >>> from z3c.pt.tal import Content
+ >>> stream = CodeIO()
+
+ >>> from StringIO import StringIO
+ >>> _out = StringIO()
+
+ >>> content = tal.Content(u"'Hello World!'")
+ >>> content.begin(stream)
+ >>> exec stream.getvalue()
+ >>> _out.getvalue()
+ 'Hello World!'
+ >>> content.end(stream)
+
+Tag
+---
+
+Define required global symbols.
+
+ >>> from cgi import escape as _escape
+ >>> _attrs = {}
+
+ >>> stream = CodeIO()
+ >>> br = Element('br')
+ >>> tag = tal.Tag(br)
+ >>> tag.begin(stream)
+ >>> tag.end(stream)
+ >>> _out = StringIO()
+ >>> exec stream.getvalue()
+ >>> _out.getvalue()
+ '<br />'
+
+ >>> stream = CodeIO()
+ >>> div = Element('div')
+ >>> div.text = ''
+ >>> tag = tal.Tag(div)
+ >>> tag.begin(stream)
+ >>> tag.end(stream)
+ >>> _out = StringIO()
+ >>> exec stream.getvalue()
+ >>> _out.getvalue()
+ '<div></div>'
Added: z3c.pt/trunk/z3c/pt/tests/__init__.py
===================================================================
Added: z3c.pt/trunk/z3c/pt/tests/helloworld.pt
===================================================================
--- z3c.pt/trunk/z3c/pt/tests/helloworld.pt (rev 0)
+++ z3c.pt/trunk/z3c/pt/tests/helloworld.pt 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,3 @@
+<div xmlns="http://www.w3.org/1999/xhtml">
+ Hello World!
+</div>
Added: z3c.pt/trunk/z3c/pt/tests/test_doctests.py
===================================================================
--- z3c.pt/trunk/z3c/pt/tests/test_doctests.py (rev 0)
+++ z3c.pt/trunk/z3c/pt/tests/test_doctests.py 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,23 @@
+import zope.testing
+import unittest
+
+OPTIONFLAGS = (zope.testing.doctest.REPORT_ONLY_FIRST_FAILURE |
+ zope.testing.doctest.ELLIPSIS |
+# zope.testing.doctest.REPORT_NDIFF |
+ zope.testing.doctest.NORMALIZE_WHITESPACE)
+
+import zope.component.testing
+
+def test_suite():
+ doctests = ['README.txt', 'BENCHMARKS.txt', 'tal.txt', 'translate.txt']
+
+ return unittest.TestSuite((
+ zope.testing.doctest.DocFileSuite(doctest,
+ optionflags=OPTIONFLAGS,
+ setUp=zope.component.testing.setUp,
+ tearDown=zope.component.testing.tearDown,
+ package="z3c.pt") for doctest in doctests
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: z3c.pt/trunk/z3c/pt/translate.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/translate.txt (rev 0)
+++ z3c.pt/trunk/z3c/pt/translate.txt 2007-12-03 15:00:50 UTC (rev 82096)
@@ -0,0 +1,60 @@
+Translation
+-----------
+
+ >>> from z3c.pt.pagetemplate import translate
+ >>> from z3c.pt import io
+
+A few imports.
+
+ >>> from lxml import etree
+ >>> from StringIO import StringIO
+
+The following symbols are expected to be in the local symbol table.
+
+ >>> from cgi import escape as _escape
+ >>> from z3c.pt.tal import repeatdict as _repeat
+ >>> repeat = _repeat()
+ >>> _attrs = {}
+
+Example:
+
+ >>> tree = etree.fromstring("""\
+ ... <div xmlns="http://www.w3.org/1999/xhtml"
+ ... xmlns:tal="http://xml.zope.org/namespaces/tal">
+ ... <span tal:define="a 'abc'"
+ ... tal:attributes="class 'def' + a"
+ ... tal:content="a + 'ghi'" />
+ ... <ul>
+ ... <li tal:repeat="i range(5)">
+ ... <span tal:replace="'Item ' + str(i) + ')'" />
+ ... </li>
+ ... </ul>
+ ... </div>
+ ... """)
+
+ >>> stream = io.CodeIO(indentation_string=" ")
+ >>> translate(tree, stream)
+ >>> _out = StringIO()
+ >>> _scope = []
+ >>> exec stream.getvalue()
+ >>> print _out.getvalue()
+ <div>
+ <span class="defabc">abcghi</span>
+ <ul>
+ <li>
+ Item 0)
+ </li>
+ <li>
+ Item 1)
+ </li>
+ <li>
+ Item 2)
+ </li>
+ <li>
+ Item 3)
+ </li>
+ <li>
+ Item 4)
+ </li>
+ </ul>
+ </div>
More information about the Checkins
mailing list