[Checkins] SVN: z3c.pt/trunk/ Compiler moved out to chameleon.core and chameleon.zpt packages.
Malthe Borch
mborch at gmail.com
Thu Oct 2 15:46:06 EDT 2008
Log message for revision 91672:
Compiler moved out to chameleon.core and chameleon.zpt packages.
Changed:
U z3c.pt/trunk/CHANGES.txt
U z3c.pt/trunk/README.txt
U z3c.pt/trunk/benchmark/benchmark/tests.py
U z3c.pt/trunk/buildout.cfg
U z3c.pt/trunk/setup.py
A z3c.pt/trunk/src/z3c/pt/README.txt
D z3c.pt/trunk/src/z3c/pt/clauses.py
D z3c.pt/trunk/src/z3c/pt/codegen.py
D z3c.pt/trunk/src/z3c/pt/codegen.txt
D z3c.pt/trunk/src/z3c/pt/config.py
U z3c.pt/trunk/src/z3c/pt/configure.zcml
D z3c.pt/trunk/src/z3c/pt/doctypes.py
D z3c.pt/trunk/src/z3c/pt/etree.py
U z3c.pt/trunk/src/z3c/pt/expressions.py
D z3c.pt/trunk/src/z3c/pt/filecache.py
D z3c.pt/trunk/src/z3c/pt/generation.py
D z3c.pt/trunk/src/z3c/pt/genshi.py
D z3c.pt/trunk/src/z3c/pt/genshi.txt
D z3c.pt/trunk/src/z3c/pt/interfaces.py
U z3c.pt/trunk/src/z3c/pt/loader.py
U z3c.pt/trunk/src/z3c/pt/pagetemplate.py
D z3c.pt/trunk/src/z3c/pt/template.py
D z3c.pt/trunk/src/z3c/pt/template.txt
D z3c.pt/trunk/src/z3c/pt/testing.py
U z3c.pt/trunk/src/z3c/pt/tests/test_doctests.py
D z3c.pt/trunk/src/z3c/pt/tests/test_edgecases.py
U z3c.pt/trunk/src/z3c/pt/tests/view.pt
D z3c.pt/trunk/src/z3c/pt/tests/xinclude1.pt
D z3c.pt/trunk/src/z3c/pt/tests/xinclude2.pt
D z3c.pt/trunk/src/z3c/pt/tests/xinclude3.pt
D z3c.pt/trunk/src/z3c/pt/tests/xinclude4.pt
U z3c.pt/trunk/src/z3c/pt/texttemplate.py
D z3c.pt/trunk/src/z3c/pt/transformer.py
D z3c.pt/trunk/src/z3c/pt/translation.py
D z3c.pt/trunk/src/z3c/pt/translation.txt
D z3c.pt/trunk/src/z3c/pt/types.py
D z3c.pt/trunk/src/z3c/pt/utils.py
D z3c.pt/trunk/src/z3c/pt/zpt.py
D z3c.pt/trunk/src/z3c/pt/zpt.txt
-=-
Modified: z3c.pt/trunk/CHANGES.txt
===================================================================
--- z3c.pt/trunk/CHANGES.txt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/CHANGES.txt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -4,6 +4,10 @@
Version 1.0dev
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Package changes
+
+- Split out compiler to "Chameleon" package. [malthe]
+
Backwards incompatibilities
- Moved contents of ``z3c.pt.macro`` module into
Modified: z3c.pt/trunk/README.txt
===================================================================
--- z3c.pt/trunk/README.txt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/README.txt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,78 +1,10 @@
Overview
---------
+========
-The z3c.pt package provides a fast template engine that supports the
-following dialects of the attribute template language:
+This package extends ``chameleon.zpt`` to provide application-level
+template support corresponding to ``zope.app.pagetemplate``, but using
+the fast Chameleon engine to compile templates into byte-code.
-* Zope TAL
-* Zope METAL
-* Zope i18n
-* Genshi
+For usage, see the README.txt file inside the package.
-Non-structural documents are supported through Genshi's variable
-interpolation syntax which is also available for XML templates.
-Casual benchmarks pegs it 16x more performant than the reference
-implementations for Zope TAL and Genshi.
-
-In a nutshell:
-
-* Templates are serialized and compiled into Python bytecode
-* Pluggable expression implementation
-
-
-Usage
------
-
-See README.txt inside package for general usage; to register the
-default expression types, load the package component configuration
-file (configure.zcml).
-
-
-Compiler notes
---------------
-
-The compiler is largely compatible with the targeted dialects. The TAL
-implementation is based on the 1.4 language specification* while the
-Genshi implementation is based on the documents for the 0.5 release**.
-
-Some notable changes:
-
-1. Tuple unpacking is allowed when defining variables:
-
- tal:define="(a, b, c) [1, 2, 3]"
-
-2. Generators are allowed in tal:repeat statements. Note that the
- repeat variable is not available in this case.
-
- tal:repeat="i <some generator>"
-
-3. Attribute-access to dictionary entries is allowed in
- Python-expressions, e.g.
-
- dictionary.key
-
- can be used instead of ``dictionary['key']``.
-
-4. Default expression type can be set using ``tal:default-expression``.
- This is an alternative to providing the expression type before each
- expression.
-
-5. The XPath select function provided to py:match-elements uses lxml
- and requires the use of the default namespace prefix "xmlns".
-
-.. _TAL: http://wiki.zope.org/ZPT/TALSpecification14
-.. _Genshi: http://genshi.edgewall.org/wiki/Documentation/xml-templates.html
-
-
-Development
------------
-
-If you want to use the code directly from trunk (recommended only for
-development and testing usage), provide ``z3c.pt==dev`` as your
-dependency.
-
-svn://svn.zope.org/repos/main/z3c.pt/trunk#egg=z3c.pt-dev
-
-Want to contribute? Join #zope3-dev on Freenode IRC.
-
Modified: z3c.pt/trunk/benchmark/benchmark/tests.py
===================================================================
--- z3c.pt/trunk/benchmark/benchmark/tests.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/benchmark/benchmark/tests.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -11,8 +11,9 @@
import zope.pagetemplate.pagetemplatefile
import z3c.pt
-from z3c.pt import config
-from z3c.pt import filecache
+from chameleon.core import config
+from chameleon.core import filecache
+
from z3c.pt import pagetemplate
from lxml import etree
@@ -63,7 +64,7 @@
class BenchmarkTestCase(BaseTestCase):
- helloworld_z3c = pagetemplate.PageTemplate("""\
+ helloworld_z3c = pagetemplate.ZopePageTemplate("""\
<div xmlns="http://www.w3.org/1999/xhtml">
Hello World!
</div>""")
@@ -86,7 +87,7 @@
</tr>
</table>""")
- bigtable_path_z3c = pagetemplate.PageTemplate("""\
+ bigtable_path_z3c = pagetemplate.ZopePageTemplate("""\
<table xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal"
tal:default-expression="path">
@@ -229,7 +230,7 @@
def testBigTablePathFile(self):
table = self.table
- z3cfile = pagetemplate.PageTemplateFile(
+ z3cfile = pagetemplate.ZopePageTemplateFile(
self._testfile('bigtable_path_z3c.pt'))
zopefile = zope.pagetemplate.pagetemplatefile.PageTemplateFile(
Modified: z3c.pt/trunk/buildout.cfg
===================================================================
--- z3c.pt/trunk/buildout.cfg 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/buildout.cfg 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,8 +1,6 @@
[buildout]
-develop =
- .
- benchmark
-
+develop = . benchmark
+
parts =
test
test-nolxml
Modified: z3c.pt/trunk/setup.py
===================================================================
--- z3c.pt/trunk/setup.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/setup.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -9,6 +9,7 @@
'zope.i18n >= 3.5',
'zope.traversing',
'zope.contentprovider',
+ 'chameleon.zpt',
]
if sys.version_info[:3] < (2,5,0):
Copied: z3c.pt/trunk/src/z3c/pt/README.txt (from rev 91339, z3c.pt/trunk/src/z3c/pt/template.txt)
===================================================================
--- z3c.pt/trunk/src/z3c/pt/README.txt (rev 0)
+++ z3c.pt/trunk/src/z3c/pt/README.txt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -0,0 +1,99 @@
+z3c.pt
+======
+
+This section demonstrates the high-level template classes. All page
+template classes in ``z3c.pt`` use path-expressions by default.
+
+Page templates
+--------------
+
+ >>> from z3c.pt.pagetemplate import ZopePageTemplate
+ >>> from z3c.pt.pagetemplate import ZopePageTemplateFile
+
+The ``ZopePageTemplate`` class is initialized with a string.
+
+ >>> print ZopePageTemplate("""\
+ ... <div xmlns="http://www.w3.org/1999/xhtml">
+ ... Hello World!
+ ... </div>""")()
+ <div>
+ Hello World!
+ </div>
+
+The ``ZopePageTemplateFile`` class is initialized with an absolute
+path to a template file on disk.
+
+ >>> from z3c.pt import tests
+ >>> path = tests.__path__[0]
+ >>> t = ZopePageTemplateFile(path+'/helloworld.pt')
+ >>> print t()
+ <div>
+ Hello World!
+ </div>
+
+ >>> import os
+ >>> t.filename.startswith(os.sep)
+ True
+
+View page templates
+-------------------
+
+ >>> from z3c.pt.pagetemplate import ViewPageTemplate
+ >>> from z3c.pt.pagetemplate import ViewPageTemplateFile
+
+ >>> class View(object):
+ ... request = u'request'
+ ... context = u'context'
+ ...
+ ... def __repr__(self):
+ ... return 'view'
+
+ >>> view = View()
+
+As before, we can initialize view page templates with a string (here
+incidentally loaded from disk).
+
+ >>> template = ViewPageTemplate(
+ ... open(path+'/view.pt').read())
+
+To render the template in the context of a view, we bind the template
+passing the view as an argument (view page templates derive from the
+``property``-class and are usually defined as an attribute on a view
+class).
+
+ >>> print template.bind(view)(test=u'test')
+ <div>
+ <span>view</span>
+ <span>context</span>
+ <span>request</span>
+ <span>test</span>
+ </div>
+
+The exercise is similar for the file-based variant.
+
+ >>> template = ViewPageTemplateFile(path+'/view.pt')
+ >>> print template.bind(view)(test=u'test')
+ <div>
+ <span>view</span>
+ <span>context</span>
+ <span>request</span>
+ <span>test</span>
+ </div>
+
+Text templates
+--------------
+
+ >>> from z3c.pt.texttemplate import ViewTextTemplate
+ >>> from z3c.pt.texttemplate import ViewTextTemplateFile
+
+ >>> template = ViewTextTemplate(open(path+'/view.css').read())
+ >>> print template.bind(view)(color=u'#ccc')
+ #region {
+ background: #ccc;
+ }
+
+ >>> template = ViewTextTemplateFile(path+'/view.css')
+ >>> print template.bind(view)(color=u'#ccc')
+ #region {
+ background: #ccc;
+ }
Deleted: z3c.pt/trunk/src/z3c/pt/clauses.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/clauses.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/clauses.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,930 +0,0 @@
-from z3c.pt import types
-from z3c.pt import config
-from z3c.pt import etree
-from z3c.pt import utils
-
-class Assign(object):
- """
- >>> from z3c.pt import testing
-
- We'll define some values for use in the tests.
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> one = types.value("1")
- >>> bad_float = types.value("float('abc')")
- >>> abc = types.value("'abc'")
- >>> ghi = types.value("'ghi'")
- >>> exclamation = types.value("'!'")
-
- Simple value assignment:
-
- >>> assign = Assign(one)
- >>> assign.begin(stream, 'a')
- >>> exec stream.getvalue()
- >>> a == 1
- True
- >>> assign.end(stream)
-
- Try-except parts (bad, good):
-
- >>> assign = Assign(types.parts((bad_float, one)))
- >>> assign.begin(stream, 'b')
- >>> exec stream.getvalue()
- >>> b == 1
- True
- >>> assign.end(stream)
-
- Try-except parts (good, bad):
-
- >>> assign = Assign(types.parts((one, bad_float)))
- >>> assign.begin(stream, 'b')
- >>> exec stream.getvalue()
- >>> b == 1
- True
- >>> assign.end(stream)
-
- Join:
-
- >>> assign = Assign(types.join((abc, ghi)))
- >>> assign.begin(stream, 'b')
- >>> exec stream.getvalue()
- >>> b == 'abcghi'
- True
- >>> assign.end(stream)
-
- Join with try-except parts:
-
- >>> assign = Assign(types.join((types.parts((bad_float, abc, ghi)), ghi)))
- >>> assign.begin(stream, 'b')
- >>> exec stream.getvalue()
- >>> b == 'abcghi'
- True
- >>> assign.end(stream)
- """
-
- def __init__(self, parts, variable=None):
- if not isinstance(parts, types.parts):
- parts = types.parts((parts,))
-
- self.parts = parts
- self.variable = variable
-
- def begin(self, stream, variable=None):
- """First n - 1 expressions must be try-except wrapped."""
-
- variable = variable or self.variable
-
- for value in self.parts[:-1]:
- stream.write("try:")
- stream.indent()
-
- self._assign(variable, value, stream)
-
- stream.outdent()
- stream.write("except Exception, e:")
- stream.indent()
-
- value = self.parts[-1]
- self._assign(variable, value, stream)
-
- stream.outdent(len(self.parts)-1)
-
- def _assign(self, variable, value, stream):
- stream.annotate(value)
- symbols = stream.symbols.as_dict()
-
- if value.symbol_mapping:
- stream.symbol_mapping.update(value.symbol_mapping)
-
- if isinstance(value, types.template):
- value = types.value(value % symbols)
- if isinstance(value, types.value):
- stream.write("%s = %s" % (variable, value))
- elif isinstance(value, types.join):
- parts = []
- _v_count = 0
-
- for part in value:
- if isinstance(part, types.template):
- part = types.value(part % symbols)
- if isinstance(part, (types.parts, types.join)):
- _v = stream.save()
- assign = Assign(part, _v)
- assign.begin(stream)
- assign.end(stream)
- _v_count +=1
- parts.append(_v)
- elif isinstance(part, types.value):
- parts.append(part)
- elif isinstance(part, unicode):
- if stream.encoding:
- parts.append(repr(part.encode(stream.encoding)))
- else:
- parts.append(repr(part))
- elif isinstance(part, str):
- parts.append(repr(part))
- else:
- raise ValueError("Not able to handle %s" % type(part))
-
- format = "%s"*len(parts)
-
- stream.write("%s = '%s' %% (%s)" % (variable, format, ",".join(parts)))
-
- for i in range(_v_count):
- stream.restore()
-
- def end(self, stream):
- pass
-
-class Define(object):
- """
- >>> from z3c.pt import testing
-
- Variable scope:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> define = Define("a", testing.pyexp("b"))
- >>> b = object()
- >>> define.begin(stream)
- >>> exec stream.getvalue()
- >>> a is b
- True
- >>> del 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:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> define1 = Define("a", testing.pyexp("b"))
- >>> define2 = Define("c", testing.pyexp("d"))
- >>> d = object()
- >>> define1.begin(stream)
- >>> define2.begin(stream)
- >>> exec stream.getvalue()
- >>> a is b and c is d
- True
- >>> define2.end(stream)
- >>> define1.end(stream)
- >>> del a; del c
- >>> stream.scope[-1].remove('a'); stream.scope[-1].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
-
- Tuple assignments:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> define = Define(types.declaration(('e', 'f')), testing.pyexp("[1, 2]"))
- >>> define.begin(stream)
- >>> exec stream.getvalue()
- >>> e == 1 and f == 2
- True
- >>> define.end(stream)
-
- Verify scope is preserved on tuple assignment:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> e = None; f = None
- >>> stream.scope[-1].add('e'); stream.scope[-1].add('f')
- >>> stream.scope.append(set())
- >>> define.begin(stream)
- >>> define.end(stream)
- >>> exec stream.getvalue()
- >>> e is None and f is None
- True
-
- Using semicolons in expressions within a define:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> define = Define("a", testing.pyexp("';'"))
- >>> define.begin(stream)
- >>> exec stream.getvalue()
- >>> a
- ';'
- >>> define.end(stream)
-
- Scope:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> a = 1
- >>> stream.scope[-1].add('a')
- >>> stream.scope.append(set())
- >>> define = Define("a", testing.pyexp("2"))
- >>> define.begin(stream)
- >>> define.end(stream)
- >>> exec stream.getvalue()
- >>> a
- 1
- """
-
- assign = None
-
- def __init__(self, declaration, expression=None, dictionary=None):
- if not isinstance(declaration, types.declaration):
- declaration = types.declaration((declaration,))
-
- if len(declaration) == 1:
- variable = declaration[0]
- else:
- variable = u"(%s,)" % ", ".join(declaration)
-
- if dictionary is not None:
- variable = "%s['%s'] = %s" % (dictionary, variable, variable)
-
- if expression is not None:
- self.assign = Assign(expression, variable)
-
- self.declaration = declaration
- self.dictionary = dictionary
-
- def begin(self, stream):
- if self.declaration.global_scope:
- # if the declaration belongs to a global scope, remove this
- # symbol from previous scopes
- for scope in stream.scope:
- for variable in self.declaration:
- if variable in scope:
- scope.remove(variable)
- else:
- # save local variables already in in scope
- for var in self.declaration:
- temp = stream.save()
-
- # If we didn't set the variable in this scope already
- if var not in stream.scope[-1]:
-
- # we'll check if it's set in one of the older scopes
- for scope in stream.scope[:-1]:
- if var in scope:
- # in which case we back it up
- stream.write('%s = %s' % (temp, var))
-
- stream.scope[-1].add(var)
-
- if self.assign is not None:
- self.assign.begin(stream)
-
- def end(self, stream):
- if self.assign is not None:
- self.assign.end(stream)
-
- if not self.declaration.global_scope:
- # restore the variables that were previously in scope
- for var in reversed(self.declaration):
- temp = stream.restore()
-
- # If we set the variable in this scope already
- if var in stream.scope[-1]:
-
- # we'll check if it's set in one of the older scopes
- for scope in stream.scope[:-1]:
- if var in scope:
- # in which case we restore it
- stream.write('%s = %s' % (var, temp))
- stream.scope[-1].remove(var)
- break
- else:
- stream.write("del %s" % var)
-
-class Condition(object):
- """
- >>> from z3c.pt import testing
-
- Unlimited scope:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> true = Condition(testing.pyexp("True"))
- >>> false = Condition(testing.pyexp("False"))
- >>> true.begin(stream)
- >>> stream.write("print 'Hello'")
- >>> true.end(stream)
- >>> false.begin(stream)
- >>> stream.write("print 'Universe!'")
- >>> false.end(stream)
- >>> stream.write("print 'World!'")
- >>> exec stream.getvalue()
- Hello
- World!
-
- Finalized limited scope:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> true = Condition(testing.pyexp("True"), [Write(testing.pyexp("'Hello'"))])
- >>> false = Condition(testing.pyexp("False"), [Write(testing.pyexp("'Hallo'"))])
- >>> true.begin(stream)
- >>> true.end(stream)
- >>> false.begin(stream)
- >>> false.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- 'Hello'
-
- Open limited scope:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> true = Condition(testing.pyexp("True"), [Tag('div')], finalize=False)
- >>> false = Condition(testing.pyexp("False"), [Tag('span')], finalize=False)
- >>> true.begin(stream)
- >>> stream.out("Hello World!")
- >>> true.end(stream)
- >>> false.begin(stream)
- >>> false.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- '<div>Hello World!</div>'
-
- """
-
- def __init__(self, value, clauses=None, finalize=True):
- self.assign = Assign(value)
- self.clauses = clauses
- self.finalize = finalize
-
- def begin(self, stream):
- temp = stream.save()
- self.assign.begin(stream, temp)
- stream.write("if %s:" % temp)
- stream.indent()
- if self.clauses:
- for clause in self.clauses:
- clause.begin(stream)
- if self.finalize:
- for clause in reversed(self.clauses):
- clause.end(stream)
- stream.outdent()
-
- def end(self, stream):
- temp = stream.restore()
-
- if self.clauses:
- if not self.finalize:
- stream.write("if %s:" % temp)
- stream.indent()
- for clause in reversed(self.clauses):
- clause.end(stream)
- stream.outdent()
- else:
- stream.outdent()
- self.assign.end(stream)
-
-class Else(object):
- def __init__(self, clauses=None):
- self.clauses = clauses
-
- def begin(self, stream):
- stream.write("else:")
- stream.indent()
- if self.clauses:
- for clause in self.clauses:
- clause.begin(stream)
- for clause in reversed(self.clauses):
- clause.end(stream)
- stream.outdent()
-
- def end(self, stream):
- if not self.clauses:
- stream.outdent()
-
-class Group(object):
- def __init__(self, clauses):
- self.clauses = clauses
-
- def begin(self, stream):
- for clause in self.clauses:
- clause.begin(stream)
- for clause in reversed(self.clauses):
- clause.end(stream)
-
- def end(self, stream):
- pass
-
-class Visit(object):
- def __init__(self, node):
- self.node = node
-
- def begin(self, stream):
- self.node.visit()
-
- def end(self, stream):
- pass
-
-class Tag(object):
- """
- >>> from z3c.pt import testing
-
- Dynamic attribute:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> tag = Tag('div', dict(alt=testing.pyexp(repr('Hello World!'))))
- >>> tag.begin(stream)
- >>> stream.out('Hello Universe!')
- >>> tag.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- '<div alt="Hello World!">Hello Universe!</div>'
-
- Self-closing tag:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> tag = Tag('br', {}, True)
- >>> tag.begin(stream)
- >>> tag.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- '<br />'
-
- Unicode:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> tag = Tag('div', dict(alt=testing.pyexp(repr('La Pe\xc3\xb1a'))))
- >>> tag.begin(stream)
- >>> stream.out('Hello Universe!')
- >>> tag.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue() == '<div alt="La Pe\xc3\xb1a">Hello Universe!</div>'
- True
-
- """
-
- def __init__(self, tag, attributes=None,
- selfclosing=False, expression=None, cdata=False):
- self.tag = tag.split('}')[-1]
- self.selfclosing = selfclosing
- self.attributes = attributes or {}
- self.expression = expression and Assign(expression)
- self.cdata = cdata
-
- def begin(self, stream):
- if self.cdata:
- stream.out('<![CDATA['); return
-
- stream.out('<%s' % self.tag)
-
- static = filter(
- lambda (attribute, value): \
- not isinstance(value, types.expression),
- self.attributes.items())
-
- # sort static attribute alphabetically by name
- static.sort(key=lambda (name, value): name)
-
- dynamic = filter(
- lambda (attribute, value): \
- isinstance(value, types.expression),
- self.attributes.items())
-
- temp = stream.save()
- temp2 = stream.save()
-
- if self.expression:
- self.expression.begin(stream, stream.symbols.tmp)
- # loop over all attributes
- stream.write("for %s, %s in %s.items():" % \
- (temp, temp2, stream.symbols.tmp))
- stream.indent()
-
- # only include attribute if expression is not None
- stream.write("if %s is not None:" % temp2)
- stream.indent()
-
- # if an encoding is specified, we need to check
- # whether we're dealing with unicode strings or not,
- # before writing out the attribute
- if stream.encoding is not None:
- # attribute name
- stream.write("if isinstance(%s, unicode):" % temp)
- stream.indent()
- stream.write("%s = %s.encode('%s')" % (temp, temp, stream.encoding))
- stream.outdent()
-
- # attribute expression
- stream.write("if isinstance(%s, unicode):" % temp2)
- stream.indent()
- stream.write("%s = %s.encode('%s')" % (temp2, temp2, stream.encoding))
- stream.outdent()
- stream.write("elif not isinstance(%s, str):" % temp2)
- else:
- stream.write("if not isinstance(%s, (str, unicode)):" % temp2)
-
- # make sure this is a string
- stream.indent()
- stream.write("%s = str(%s)" % (temp2, temp2))
- stream.outdent()
-
- # escape expression
- stream.escape(temp2)
-
- # write out
- stream.write("%s(' %%s=\"%%s\"' %% (%s, %s))" % \
- (stream.symbols.write, temp, temp2))
-
- stream.outdent()
- stream.outdent()
-
- for attribute, value in dynamic:
- assign = Assign(value)
- assign.begin(stream, temp)
-
- # only include attribute if expression is not ``None`` or ``False``
- stream.write("if %s is not None and %s is not False:" % (temp, temp))
- stream.indent()
-
- # if an encoding is specified, we need to check
- # whether we're dealing with unicode strings or not,
- # before writing out the attribute
- if stream.encoding is not None:
- stream.write("if isinstance(%s, unicode):" % temp)
- stream.indent()
- stream.write("%s = %s.encode('%s')" % (temp, temp, stream.encoding))
- stream.outdent()
- stream.write("elif not isinstance(%s, str):" % temp)
- else:
- stream.write("if not isinstance(%s, (str, unicode)):" % temp)
-
- # make sure this is a string
- stream.indent()
- stream.write("%s = str(%s)" % (temp, temp))
- stream.outdent()
-
- # escape expression
- stream.escape(temp)
-
- # print attribute
- stream.write("%s(' %s=\"'+%s+'\"')" % (
- stream.symbols.write, attribute, temp))
-
- stream.outdent()
- assign.end(stream)
-
- stream.restore()
- stream.restore()
-
- for attribute, expression in static:
- if isinstance(expression, unicode) and stream.encoding:
- expression = expression.encode(stream.encoding)
-
- # escape expression
- expression = utils.escape(expression, '"', stream.encoding)
-
- # if there are dynamic expressions, we only want to write
- # out static attributes if they're not in the dynamic
- # expression dictionary
- if self.expression:
- stream.write("if '%s' not in %s:" % (attribute, stream.symbols.tmp))
- stream.indent()
-
- stream.out(' %s="%s"' % (attribute, expression))
-
- if self.expression:
- stream.outdent()
-
- if self.selfclosing:
- stream.out(" />")
- else:
- stream.out(">")
-
- def end(self, stream):
- if self.cdata:
- stream.out(']]>'); return
-
- if not self.selfclosing:
- stream.out('</%s>' % self.tag)
-
-class Repeat(object):
- """
- >>> from z3c.pt import testing
-
- We need to set up the repeat object.
-
- >>> from z3c.pt import utils
- >>> repeat = utils.repeatdict()
-
- Simple repeat loop and repeat data structure:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> _repeat = Repeat("i", testing.pyexp("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())")
- >>> _repeat.end(stream)
- >>> 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)
-
- A repeat over an empty set.
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> _repeat = Repeat("j", testing.pyexp("range(0)"))
- >>> _repeat.begin(stream)
- >>> _repeat.end(stream)
- >>> exec stream.getvalue()
-
- A repeat over a non-iterable raises an exception.
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> _repeat = Repeat("j", testing.pyexp("None"))
- >>> _repeat.begin(stream)
- >>> _repeat.end(stream)
- >>> exec stream.getvalue()
- Traceback (most recent call last):
- ...
- TypeError: Can only repeat over an iterable object (None).
-
- Simple for loop:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> _for = Repeat("i", testing.pyexp("range(3)"), repeatdict=False)
- >>> _for.begin(stream)
- >>> stream.write("print i")
- >>> _for.end(stream)
- >>> exec stream.getvalue()
- 0
- 1
- 2
- >>> _for.end(stream)
-
- """
-
- def __init__(self, v, e, scope=(), repeatdict=True):
- self.variable = v
- self.expression = e
- self.define = Define(v)
- self.assign = Assign(e)
- self.repeatdict = repeatdict
-
- def begin(self, stream):
- variable = self.variable
-
- if self.repeatdict:
- # initialize variable scope
- self.define.begin(stream)
-
- # assign iterator
- iterator = stream.save()
- self.assign.begin(stream, iterator)
-
- # initialize iterator
- stream.write("%s = repeat.insert('%s', %s)" % (
- iterator, variable, iterator))
-
- # loop
- stream.write("try:")
- stream.indent()
- stream.write("%s = None" % variable)
- stream.write("%s = %s.next()" % (variable, iterator))
- stream.write("while True:")
- stream.indent()
- else:
- stream.write("for %s in %s:" % (variable, self.expression))
- stream.indent()
-
- def end(self, stream):
- # cook before leaving loop
- stream.cook()
-
- if self.repeatdict:
- iterator = stream.restore()
- stream.write("%s = %s.next()" % (self.variable, iterator))
-
- stream.out('\n')
- stream.outdent()
-
- if self.repeatdict:
- stream.outdent()
- stream.write("except StopIteration:")
- stream.indent()
- stream.write("pass")
- stream.outdent()
-
- self.define.end(stream)
- self.assign.end(stream)
-
-class Write(object):
- """
- >>> from z3c.pt import testing
-
- Basic write:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> write = Write(testing.pyexp("'New York'"))
- >>> write.begin(stream)
- >>> write.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- 'New York'
-
- Try-except parts:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> write = Write(testing.pyexp("undefined | 'New Delhi'"))
- >>> write.begin(stream)
- >>> write.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- 'New Delhi'
-
- Unicode:
-
- >>> _out, _write, stream = testing.setup_stream('utf-8')
- >>> write = Write(types.value(repr('La Pe\xc3\xb1a'.decode('utf-8'))))
- >>> write.begin(stream)
- >>> write.end(stream)
- >>> exec stream.getvalue()
- >>> val = _out.getvalue()
- >>> val == 'La Pe\xc3\xb1a'
- True
- >>> type(val) == str
- True
- """
-
- value = assign = None
-
- def __init__(self, value):
- self.assign = Assign(value)
- self.structure = not isinstance(value, types.escape)
-
- def begin(self, stream):
- temp = stream.save()
- symbols = stream.symbols.as_dict()
- value = self.value
-
- if isinstance(value, types.template):
- value = types.value(value % symbols)
-
- def write(template):
- stream.write(template % symbols)
-
- if value:
- expr = value
- else:
- self.assign.begin(stream, temp)
- expr = temp
-
- stream.write("%s = %s" % (stream.symbols.tmp, expr))
- write("if %(tmp)s is not None:")
- stream.indent()
-
- if stream.encoding is not None:
- write("if isinstance(%(tmp)s, unicode):")
- stream.indent()
- write("%%(tmp)s = %%(tmp)s.encode('%s')" % stream.encoding)
- stream.outdent()
- write("elif not isinstance(%(tmp)s, str):")
- else:
- write("if not isinstance(%(tmp)s, (str, unicode)):")
-
- # make sure this is a string
- stream.indent()
- write("%(tmp)s = str(%(tmp)s)")
- stream.outdent()
-
- if self.structure:
- write("%(write)s(%(tmp)s)")
- else:
- stream.escape(stream.symbols.tmp)
- write("%(write)s(%(tmp)s)")
-
- stream.outdent()
-
- # validate XML if enabled
- if config.VALIDATION:
- try:
- _et = etree.import_elementtree()
- except ImportError:
- raise ImportError(
- "ElementTree (required when XML validation is enabled).")
-
- stream.symbol_mapping[stream.symbols.validate] = etree.validate
- write("%(validate)s(%(tmp)s)")
-
- def end(self, stream):
- if self.assign:
- self.assign.end(stream)
- stream.restore()
-
-class UnicodeWrite(Write):
- """
- >>> from z3c.pt import testing
-
- Basic write:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> write = Write(types.value("'New York'"))
- >>> write.begin(stream)
- >>> write.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- 'New York'
-
- Unicode:
-
- >>> _out, _write, stream = testing.setup_stream('utf-8')
- >>> write = Write(types.value(repr(unicode('La Pe\xc3\xb1a', 'utf-8'))))
- >>> write.begin(stream)
- >>> write.end(stream)
- >>> exec stream.getvalue()
- >>> val = _out.getvalue()
- >>> val == 'La Pe\xc3\xb1a'
- True
- >>> type(val) == str
- True
-
- Invalid:
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> write = Write(types.value("None"))
- >>> write.begin(stream)
- >>> write.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- ''
- """
-
- def begin(self, stream):
- temp = stream.save()
-
- if self.value:
- expr = self.value
- else:
- self.assign.begin(stream, temp)
- expr = temp
-
- stream.write("%s(%s)" % (stream.symbols.write, expr))
-
-class Out(object):
- """
- >>> from z3c.pt import testing
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> out = Out('Hello World!')
- >>> out.begin(stream)
- >>> out.end(stream)
- >>> exec stream.getvalue()
- >>> _out.getvalue()
- 'Hello World!'
- """
-
- def __init__(self, string, defer=False):
- self.string = string
- self.defer = defer
-
- def begin(self, stream):
- if not self.defer:
- stream.out(self.string)
-
- def end(self, stream):
- stream.cook()
- if self.defer:
- stream.out(self.string)
-
-class Method(object):
- """
- >>> from z3c.pt import testing
-
- >>> _out, _write, stream = testing.setup_stream()
- >>> _scope = {}
- >>> method = Method('test', ('a', 'b', 'c'))
- >>> method.begin(stream)
- >>> stream.write('print a, b, c')
- >>> method.end(stream)
- >>> exec stream.getvalue()
- >>> test(1, 2, 3)
- 1 2 3
-
- """
-
- def __init__(self, name, args):
- self.name = name
- self.args = args
-
- def begin(self, stream):
- stream.write('def %s(%s):' % (self.name, ", ".join(self.args)))
- stream.indent()
-
- def end(self, stream):
- stream.outdent()
- assign = Assign(
- types.value(self.name), "%s['%s']" % \
- (stream.symbols.scope, self.name))
- assign.begin(stream)
- assign.end(stream)
Deleted: z3c.pt/trunk/src/z3c/pt/codegen.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/codegen.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/codegen.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,190 +0,0 @@
-from compiler import ast, parse
-from compiler.pycodegen import ModuleCodeGenerator
-
-from transformer import ASTTransformer
-
-import __builtin__
-
-CONSTANTS = frozenset(['False', 'True', 'None', 'NotImplemented', 'Ellipsis'])
-UNDEFINED = object()
-
-def flatten(list):
- """Flattens a potentially nested sequence into a flat list.
- """
- l = []
- for elt in list:
- t = type(elt)
- if t is set or t is tuple or t is list or t is frozenset:
- for elt2 in flatten(elt):
- l.append(elt2)
- else:
- l.append(elt)
- return l
-
-class Lookup(object):
- """Abstract base class for variable lookup implementations."""
-
- @classmethod
- def globals(cls):
- """Construct the globals dictionary to use as the execution context for
- the expression or suite.
- """
- return {
- '_lookup_attr': cls.lookup_attr,
- '_lookup_name': cls.lookup_name,
- }
-
- @classmethod
- def lookup_attr(cls, obj, key):
- try:
- return getattr(obj, key)
- except AttributeError, e:
- try:
- return obj[key]
- except (KeyError, TypeError):
- raise e
-
- @classmethod
- def lookup_name(cls, data, name):
- try:
- return data[name]
- except KeyError:
- raise NameError(name)
-
-class TemplateASTTransformer(ASTTransformer):
- """Concrete AST transformer that implements the AST transformations needed
- for code embedded in templates.
-
- """
-
- def __init__(self, globals):
- self.locals = [CONSTANTS]
- builtin = dir(__builtin__)
- self.locals.append(set(globals))
- self.locals.append(set(builtin))
- # self.names is an optimization for visitName (so we don't
- # need to flatten the locals every time it's called)
- self.names = set()
- self.names.update(CONSTANTS)
- self.names.update(builtin)
- self.names.update(globals)
-
- def visitConst(self, node):
- #if isinstance(node.value, unicode):
- # return ast.Const(node.value.encode('utf-8'))
- return node
-
- def visitAssName(self, node):
- if len(self.locals) > 1:
- if node.flags == 'OP_ASSIGN':
- self.locals[-1].add(node.name)
- self.names.add(node.name)
- else:
- self.locals[-1].remove(node.name)
- self.names.remove(node.name)
- return node
-
- def visitClass(self, node):
- if len(self.locals) > 1:
- self.locals[-1].add(node.name)
- self.names.add(node.name)
- self.locals.append(set())
- try:
- return ASTTransformer.visitClass(self, node)
- finally:
- self.locals.pop()
-
- def visitFor(self, node):
- self.locals.append(set())
- try:
- return ASTTransformer.visitFor(self, node)
- finally:
- self.locals.pop()
-
- def visitFunction(self, node):
- if len(self.locals) > 1:
- self.locals[-1].add(node.name)
- self.names.add(node.name)
- self.locals.append(set(node.argnames))
- self.names.update(node.argnames)
- try:
- return ASTTransformer.visitFunction(self, node)
- finally:
- self.locals.pop()
-
- def visitGenExpr(self, node):
- self.locals.append(set())
- try:
- return ASTTransformer.visitGenExpr(self, node)
- finally:
- self.locals.pop()
-
- def visitLambda(self, node):
- argnames = flatten(node.argnames)
- self.names.update(argnames)
- self.locals.append(set(argnames))
- try:
- return ASTTransformer.visitLambda(self, node)
- finally:
- self.locals.pop()
-
- def visitListComp(self, node):
- self.locals.append(set())
- try:
- return ASTTransformer.visitListComp(self, node)
- finally:
- self.locals.pop()
-
- def visitName(self, node):
- # If the name refers to a local inside a lambda, list comprehension, or
- # generator expression, leave it alone
- if not node.name in self.names:
- # Otherwise, translate the name ref into a context lookup
- func_args = [ast.Name('_scope'), ast.Const(node.name)]
- node = ast.CallFunc(ast.Name('_lookup_name'), func_args)
- return node
-
- def visitGetattr(self, node):
- """Get attribute with fallback to dictionary lookup.
-
- Note: Variables starting with an underscore are exempt
- (reserved for internal use).
- """
-
- if hasattr(node.expr, 'name') and node.expr.name.startswith('_'):
- return ast.Getattr(node.expr, node.attrname)
-
- return ast.CallFunc(ast.Name('_lookup_attr'), [
- self.visit(node.expr), ast.Const(node.attrname)
- ])
-
-class Suite(object):
- __slots__ = ['code', '_globals']
-
- mode = 'exec'
-
- def __init__(self, source, globals=()):
- """Create the code object from a string."""
-
- if isinstance(source, unicode):
- source = source.encode('utf-8')
-
- node = parse(source, self.mode)
-
- # build tree
- transform = TemplateASTTransformer(globals)
- tree = transform.visit(node)
- filename = tree.filename = '<script>'
-
- # generate code
- gen = ModuleCodeGenerator(tree)
- gen.optimized = True
-
- self._globals = Lookup.globals()
- self.code = gen.getCode()
-
- def __hash__(self):
- return hash(self.code)
-
- def __repr__(self):
- return '%s(%r)' % (self.__class__.__name__, self.code)
Deleted: z3c.pt/trunk/src/z3c/pt/codegen.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/codegen.txt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/codegen.txt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,40 +0,0 @@
-Codegen
-=======
-
-The ``Codegen`` module is responsible for the low-level compilation
-of the page template.
-
-Suite
------
-
-The ``Suite`` class compiles a source code suite and makes a code
-object available.
-
- >>> from z3c.pt.codegen import Suite
- >>> suite = Suite("""\
- ... print 'Hello World!'
- ... """)
- >>> exec suite.code in suite._globals
- Hello World!
-
-Syntax extension: Dictionary lookup using dot operator
-------------------------------------------------------
-
-We allow attribute access to dictionary entries to minimize verbosity
-in templates. It works by wrapping the get attribute nodes in a method
-that tries a dictionary lookup if attribute lookup failed.
-
- >>> suite = Suite("""\
- ... a = {'b': 1}
- ... assert a['b'] == a.b
- ... """)
- >>> exec suite.code in suite._globals
-
-Syntax extension: Dynamic scoping
----------------------------------
-
- >>> suite = Suite("""\
- ... _scope = {'a': 1}
- ... assert a == 1
- ... """)
- >>> exec suite.code in suite._globals
Deleted: z3c.pt/trunk/src/z3c/pt/config.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/config.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/config.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,68 +0,0 @@
-import os
-
-# define which values are read as true
-TRUEVALS = ('y', 'yes', 't', 'true', 'on', '1')
-
-# in debug-mode, templates on disk are reloaded if they're modified
-DEBUG_MODE_KEY = 'Z3C_PT_DEBUG'
-DEBUG_MODE = os.environ.get(DEBUG_MODE_KEY, 'false')
-DEBUG_MODE = DEBUG_MODE.lower() in TRUEVALS
-
-# disable disk-cache to prevent the compiler from caching on disk
-DISK_CACHE_KEY = 'Z3C_PT_CACHE'
-DISK_CACHE = os.environ.get(DISK_CACHE_KEY, 'true')
-DISK_CACHE = DISK_CACHE.lower() in TRUEVALS
-CACHE_EXTENSION = "cache"
-
-# when validation is enabled, dynamically inserted content is
-# validated against the XHTML standard
-VALIDATION = DEBUG_MODE
-
-# use the disable-i18n flag to disable the translation machinery; this
-# will speed up templates that use internationalization
-DISABLE_I18N_KEY = 'Z3C_PT_DISABLE_I18N'
-DISABLE_I18N = os.environ.get(DISABLE_I18N_KEY, 'false')
-DISABLE_I18N = DISABLE_I18N.lower() in TRUEVALS
-
-# these definitions are standard---change at your own risk!
-XHTML_NS = "http://www.w3.org/1999/xhtml"
-TAL_NS = "http://xml.zope.org/namespaces/tal"
-META_NS = "http://xml.zope.org/namespaces/meta"
-METAL_NS = "http://xml.zope.org/namespaces/metal"
-XI_NS = "http://www.w3.org/2001/XInclude"
-I18N_NS = "http://xml.zope.org/namespaces/i18n"
-PY_NS = "http://genshi.edgewall.org/"
-NS_MAP = dict(py=PY_NS, tal=TAL_NS, metal=METAL_NS)
-
-# the symbols table below is used internally be the compiler
-class SYMBOLS(object):
- # internal use only
- init = '_init'
- slot = '_slot'
- metal = '_metal'
- include = '_include'
- macro = '_macro'
- scope = '_scope'
- out = '_out'
- tmp = '_tmp'
- write = '_write'
- mapping = '_mapping'
- result = '_result'
- marker = '_marker'
- domain = '_domain'
- i18n_context = '_i18n_context'
- attributes = '_attributes'
- negotiate = '_negotiate'
- translate = '_translate'
- validate = '_validate'
- path = '_path'
-
- # advertised symbols
- repeat = 'repeat'
- language = 'target_language'
- xincludes = 'xincludes'
-
- @classmethod
- def as_dict(cls):
- return dict((name, getattr(cls, name)) for name in dir(cls))
-
Modified: z3c.pt/trunk/src/z3c/pt/configure.zcml
===================================================================
--- z3c.pt/trunk/src/z3c/pt/configure.zcml 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/configure.zcml 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,35 +1,18 @@
<configure package="z3c.pt"
- xmlns="http://namespaces.zope.org/zope"
- xmlns:zcml="http://namespaces.zope.org/zcml">
+ xmlns="http://namespaces.zope.org/zope">
<include package="zope.component" file="meta.zcml" />
+
+ <include package="chameleon.core" />
+ <include package="chameleon.zpt" />
<utility
- name="python"
- component=".expressions.python_translation" />
-
- <utility
name="path"
- component=".expressions.path_translation" />
+ component=".expressions.path_translator" />
<utility
name="provider"
- component=".expressions.provider_translation" />
+ component=".expressions.provider_translator" />
- <adapter
- name="string"
- factory=".expressions.StringTranslation" />
-
- <configure zcml:condition="installed zope.app.component">
-
- <include package="zope.app.component" file="meta.zcml" />
- <include package="zope.app.security" file="meta.zcml" />
-
- <class class=".utils.repeatitem">
- <allow interface=".interfaces.ITALESIterator" />
- </class>
-
- </configure>
-
</configure>
Deleted: z3c.pt/trunk/src/z3c/pt/doctypes.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/doctypes.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/doctypes.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,13 +0,0 @@
-def dt(name, pubid, system):
- return '<!DOCTYPE %s PUBLIC "%s" "%s">' % (name, pubid, system)
-
-html_strict = dt('HTML', '-//W3C//DTD HTML 4.01//EN',
- 'http://www.w3.org/TR/html4/strict.dtd')
-html = dt('HTML', '-//W3C//DTD HTML 4.01 Transitional//EN',
- 'http://www.w3.org/TR/html4/loose.dtd')
-xhtml_strict = dt('html', '-//W3C//DTD XHTML 1.0 Strict//EN',
- 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd')
-xhtml = dt('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
- 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')
-no_doctype = ()
-
Deleted: z3c.pt/trunk/src/z3c/pt/etree.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/etree.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/etree.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,320 +0,0 @@
-import htmlentitydefs
-import config
-import utils
-import cgi
-import copy
-import xml.parsers.expat
-from StringIO import StringIO
-
-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
- except:
- try:
- import elementtree.ElementTree as ET
- except ImportError:
- import cElementTree as ET
-
- return ET
-
-def validate(string):
- try:
- import_elementtree().fromstring("<div>%s</div>" % string)
- except xml.parsers.expat.ExpatError:
- raise ValidationError(string)
-
-class Parser(object):
- element_mapping = utils.emptydict()
-
- def parse(self, body):
- return parse(body, self.element_mapping)
-
-try:
- import lxml.etree
-
- class ElementBase(lxml.etree.ElementBase):
- def tostring(self):
- return lxml.etree.tostring(self)
-
- def _convert_cdata_sections(self):
- start = '<![CDATA['
- end = ']]>'
-
- text = self._raw_text or ""
- tail = self._raw_tail or ""
-
- if start in text:
- before, rest = text.split(start, 1)
- cdata, after = rest.split(end, 1)
-
- element = self.makeelement(
- utils.xhtml_attr('cdata'))
- element.attrib[utils.meta_attr('cdata')] = ""
- element.text = cdata
- element.tail = after
-
- self.text = before
- self.insert(0, element)
- element._convert_cdata_sections()
-
- if start in tail:
- before, rest = tail.split(start, 1)
- cdata, after = rest.split(end, 1)
-
- element = self.makeelement(
- utils.xhtml_attr('cdata'))
- element.attrib[utils.meta_attr('cdata')] = ""
- self.addnext(element)
-
- element.text = cdata
- element.tail = after
- self.tail = before
- element._convert_cdata_sections()
-
- @property
- def _raw_text(self):
- """Return raw text.
-
- CDATA sections are returned in their original formatting;
- the routine relies on the fact that ``tostring`` will
- output CDATA sections even though they're not present in
- the .text-attribute.
- """
-
- if self.text in ("", None):
- return self.text
-
- elements = tuple(self)
- del self[:]
- xml = lxml.etree.tostring(self, encoding='utf-8', with_tail=False)
- self.extend(elements)
-
- element = self.makeelement(self.tag, nsmap=self.nsmap)
- for attr, value in self.items():
- element.attrib[attr] = value
-
- html = lxml.etree.tostring(element)
- tag = len(element.tag.split('}')[-1])+3
- text = xml[len(html)-tag:-tag]
-
- return text
-
- @property
- def _raw_tail(self):
- """Return raw tail.
-
- CDATA sections are returned in their original formatting;
- the routine relies on the fact that ``tostring`` will
- output CDATA sections even though they're not present in
- the .tail-attribute.
- """
-
- if self.tail in ("", None):
- return self.tail
-
- elements = tuple(self)
- del self[:]
-
- parent = self.getparent()
- if parent is None:
- return self.tail
-
- length = len(lxml.etree.tostring(self, encoding='utf-8', with_tail=False))
-
- # wrap element
- index = parent.index(self)
- element = self.makeelement(self.tag, nsmap=self.nsmap)
- element.append(self)
- xml = lxml.etree.tostring(element, encoding='utf-8', with_tail=False)
- self.extend(elements)
- parent.insert(index, self)
-
- ns = self.tag[self.tag.find('{')+1:self.tag.find('}')]
- for prefix, namespace in self.nsmap.items():
- if ns == namespace:
- if prefix is None:
- tag = len(self.tag) - len(ns)
- else:
- tag = len(self.tag) - len(ns) + len(prefix) + 1
- break
- else:
- raise ValueError(
- "Unable to determine tag length: %s." % self.tag)
-
- tail = xml[length+tag:-tag-1]
-
- return tail
-
- def convert_cdata_section(node):
- parent = node.getparent()
- if parent is not None:
- index = parent.index(node)
- element = node.makeelement(node.tag, nsmap=node.nsmap)
- element.append(node)
- xml = lxml.etree.tostring(element, encoding='utf-8', with_tail=False)
- parent.insert(index, node)
- else:
- xml = lxml.etree.tostring(node, encoding='utf-8', with_tail=False)
-
- if 'CDATA' in xml:
- node._convert_cdata_sections()
- for child in tuple(node):
- convert_cdata_section(child)
-
- def parse(body, element_mapping):
- lookup = lxml.etree.ElementNamespaceClassLookup()
- parser = lxml.etree.XMLParser(resolve_entities=False, strip_cdata=False)
- parser.setElementClassLookup(lookup)
-
- # lxml 1.3-compatibility
- try:
- ns_lookup = lookup.get_namespace
- except AttributeError:
- ns_lookup = lxml.etree.Namespace
-
- for key, mapping in element_mapping.items():
- ns_lookup(key).update(mapping)
-
- tree = lxml.etree.parse(StringIO(body), parser)
- root = tree.getroot()
-
- convert_cdata_section(root)
-
- return root, tree.docinfo.doctype
-
-except ImportError:
- ET = import_elementtree()
- from pdis.xpath import XPath
-
- class ElementBase(object, ET._ElementInterface):
- _parent = None
-
- def __new__(cls, tag, attrs=None):
- return element_factory(tag, attrs)
-
- def __init__(self, tag, attrs=None):
- if attrs is None:
- attrs = {}
-
- ET._ElementInterface.__init__(self, tag, attrs)
-
- def getparent(self):
- return self._parent
-
- def getroottree(self):
- while self._parent is not None:
- self = self._parent
- class roottree(object):
- @classmethod
- def getroot(cls):
- return self
- return roottree
-
- def insert(self, position, element):
- element._parent = self
- ET._ElementInterface.insert(self, position, element)
-
- def tostring(self):
- return ET.tostring(self)
-
- def xpath(self, path, namespaces={}):
- xpath = XPath(path, namespace_mapping=namespaces)
- return xpath.evaluate(self)
-
- @property
- def nsmap(self):
- # TODO: Return correct namespace map
- return {None: config.XHTML_NS}
-
- @property
- def prefix(self):
- try:
- ns, prefix = self.tag.split('}')
- except:
- return None
-
- for prefix, namespace in self.nsmap.items():
- if namespace == ns:
- return prefix
-
- namespaces = {}
- def ns_lookup(ns):
- return namespaces.setdefault(ns, {})
-
- class TreeBuilder(ET.TreeBuilder):
- def start(self, tag, attrs):
- if len(self._elem):
- parent = self._elem[-1]
- else:
- parent = None
- elem = ET.TreeBuilder.start(self, tag, attrs)
- elem._parent = parent
- elem.makeelement = self._factory
-
- class XMLParser(ET.XMLParser):
- def __init__(self, **kwargs):
- ET.XMLParser.__init__(self, **kwargs)
-
- # this makes up for ET's lack of support for comments and
- # processing instructions
- self._parser.CommentHandler = self.handle_comment
- self._parser.ProcessingInstructionHandler = self.handle_pi
- self._parser.StartCdataSectionHandler = self.handle_cdata_start
- self._parser.EndCdataSectionHandler = self.handle_cdata_end
-
- def doctype(self, name, pubid, system):
- self.doctype = u'<!DOCTYPE %(name)s PUBLIC "%(pubid)s" "%(system)s">' % \
- dict(name=name, pubid=pubid, system=system)
-
- def handle_comment(self, data):
- name = utils.tal_attr('comment')
- self._target.start(name, {})
- self._target.data("<!-- %s -->" % data)
- self._target.end(name)
-
- def handle_pi(self, target, data):
- name = utils.tal_attr('pi')
- self._target.start(name, {})
- self._target.data("<?%(target)s %(data)s?>" % dict(target=target, data=data))
- self._target.end(name)
-
- def handle_cdata_start(self):
- self._target.start(utils.xhtml_attr('cdata'), {
- utils.tal_attr('cdata'): ''})
-
- def handle_cdata_end(self):
- self._target.end(utils.xhtml_attr('cdata'))
-
- def parse(body, element_mapping):
- def element_factory(tag, attrs=None, nsmap=None):
- if attrs is None:
- attrs = {}
-
- if '{' in tag:
- ns = tag[tag.find('{')+1:tag.find('}')]
- ns_tag = tag[tag.find('}')+1:]
- else:
- ns = None
- ns_tag = None
-
- namespace = element_mapping[ns]
- factory = namespace.get(ns_tag) or namespace.get(None) or ElementBase
-
- element = object.__new__(factory)
- element.__init__(tag, attrs)
-
- return element
-
- target = TreeBuilder(element_factory=element_factory)
- parser = XMLParser(target=target)
- parser.entity = dict([(name, "&%s;" % name) for name in htmlentitydefs.entitydefs])
- parser.feed(body)
- root = parser.close()
-
- return root, parser.doctype
Modified: z3c.pt/trunk/src/z3c/pt/expressions.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/expressions.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/expressions.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,3 +1,6 @@
+import parser
+import re
+
import zope.interface
import zope.component
@@ -5,651 +8,16 @@
from zope.contentprovider.interfaces import IContentProvider
from zope.contentprovider.interfaces import ContentProviderLookupError
-import parser
-import re
+from chameleon.core import types
+from chameleon.zpt import expressions
-import interfaces
-import types
-import config
-import utils
-
_marker = object()
-class ExpressionTranslation(object):
- zope.interface.implements(interfaces.IExpressionTranslation)
+def identity(x):
+ return x
- 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(';;', ';')
-
class ZopeTraverser(object):
- def __init__(self, proxify=utils.identity):
+ def __init__(self, proxify=identity):
self.proxify = proxify
def __call__(self, base, request, call, *path_items):
@@ -681,20 +49,22 @@
return base
-class PathTranslation(ExpressionTranslation):
+class PathTranslator(expressions.ExpressionTranslator):
path_regex = re.compile(
r'^((nocall|not):\s*)*([A-Za-z_][A-Za-z0-9_]*)'+
r'(/[A-Za-z_ at -][A-Za-z0-9_ at -\\.]*)*$')
path_traverse = ZopeTraverser()
+ symbol = '_path'
+
def validate(self, string):
if not self.path_regex.match(string.strip()):
raise SyntaxError("Not a valid path-expression.")
def translate(self, string):
"""
- >>> translate = PathTranslation().translate
+ >>> translate = PathTranslator().translate
>>> translate("a/b")
value("_path(a, request, True, 'b')")
@@ -740,16 +110,16 @@
value = types.value(
'%s(%s, request, %s, %s)' % \
- (config.SYMBOLS.path, base, not nocall, ', '.join(components)))
+ (self.symbol, base, not nocall, ', '.join(components)))
if negate:
value = types.value('not(%s)' % value)
- value.symbol_mapping[config.SYMBOLS.path] = self.path_traverse
+ value.symbol_mapping[self.symbol] = self.path_traverse
return value
-path_translation = PathTranslation()
+path_translator = PathTranslator()
def get_content_provider(context, request, view, name):
cp = zope.component.queryMultiAdapter(
@@ -762,9 +132,7 @@
cp.update()
return cp.render()
-class ProviderTranslation(object):
- zope.interface.implements(interfaces.IExpressionTranslation)
-
+class ProviderTranslator(expressions.ExpressionTranslator):
provider_regex = re.compile(r'^[A-Za-z][A-Za-z0-9_-]*$')
symbol = '_get_content_provider'
@@ -779,4 +147,4 @@
value.symbol_mapping[self.symbol] = get_content_provider
return value
-provider_translation = ProviderTranslation()
+provider_translator = ProviderTranslator()
Deleted: z3c.pt/trunk/src/z3c/pt/filecache.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/filecache.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/filecache.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,56 +0,0 @@
-import os
-import config
-import cPickle as pickle
-
-class TemplateCache(object):
- def __init__(self, filename):
- self.filename = filename
- self.registry = {}
- self.load()
-
- def __getitem__(self, key):
- return self.registry[key]
-
- def __setitem__(self, key, template):
- self.registry[key] = template
- self.save()
-
- def __len__(self):
- return len(self.registry)
-
- def get(self, key, default=None):
- return self.registry.get(key, default)
-
- @property
- def module_filename(self):
- return self.filename + os.extsep + config.CACHE_EXTENSION
-
- def load(self):
- try:
- module_filename = self.module_filename
- f = open(module_filename, 'rb')
- except IOError:
- return
-
- try:
- try:
- self.registry = pickle.load(f)
- except EOFError:
- pass
- finally:
- f.close()
-
- def save(self):
- try:
- f = open(self.module_filename, 'wb')
- except IOError:
- return
-
- try:
- pickle.dump(self.registry, f, protocol=2)
- finally:
- f.close()
-
- def purge(self):
- self.registry = {}
- self.save()
Deleted: z3c.pt/trunk/src/z3c/pt/generation.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/generation.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/generation.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,166 +0,0 @@
-from zope.i18n import interpolate
-from zope.i18n import translate
-from zope.i18nmessageid import Message
-
-import utils
-import etree
-import expressions
-
-template_wrapper = """\
-def render(%(init)s, %(args)s%(extra)s%(language)s=None):
-\t%(out)s, %(write)s = %(init)s.initialize_stream()
-\t%(attributes)s, %(repeat)s = %(init)s.initialize_tal()
-\t%(scope)s = {}
-\t%(domain)s = None
-
-%(body)s
-\treturn %(out)s.getvalue()
-"""
-
-macro_wrapper = """\
-def render(%(init)s, %(kwargs)s%(extra)s):
-\t%(attributes)s, %(repeat)s = %(init)s.initialize_tal()
-\t%(domain)s = None
-%(body)s
-"""
-
-class marker(object):
- pass
-
-def fast_translate(msgid, domain=None, mapping=None, context=None,
- target_language=None, default=None):
- """This translation function does not attempt to negotiate a
- language if ``None`` is passed."""
-
- if target_language is not None:
- return translate(
- msgid, domain=domain, mapping=mapping, context=context,
- target_language=target_language, default=default)
-
- if isinstance(msgid, Message):
- default = msgid.default
- mapping = msgid.mapping
-
- if default is None:
- default = unicode(msgid)
-
- if not isinstance(default, (str, unicode)):
- return default
-
- return interpolate(default, mapping)
-
-def initialize_tal():
- return ({}, utils.repeatdict())
-
-def initialize_stream():
- out = BufferIO()
- return (out, out.write)
-
-class BufferIO(list):
- write = list.append
-
- def getvalue(self):
- return ''.join(self)
-
-class CodeIO(BufferIO):
- """Stream buffer suitable for writing Python-code. This class is
- used internally by the compiler to manage variable scopes, source
- annotations and temporary variables."""
-
- t_prefix = '_tmp'
- v_prefix = '_var'
-
- def __init__(self, symbols=None, encoding=None,
- indentation=0, indentation_string="\t"):
- BufferIO.__init__(self)
- self.symbols = symbols or object
- self.symbol_mapping = {}
- self.encoding = encoding
- self.indentation = indentation
- self.indentation_string = indentation_string
- self.queue = ''
- self.scope = [set()]
- self.selectors = {}
- self.annotations = {}
- self._variables = {}
- self.t_counter = 0
- self.l_counter = 0
-
- def save(self):
- self.t_counter += 1
- return "%s%d" % (self.t_prefix, self.t_counter)
-
- def restore(self):
- var = "%s%d" % (self.t_prefix, self.t_counter)
- self.t_counter -= 1
- return var
-
- def indent(self, amount=1):
- if amount > 0:
- self.cook()
- self.indentation += amount
-
- def outdent(self, amount=1):
- if amount > 0:
- self.cook()
- self.indentation -= amount
-
- def annotate(self, item):
- self.annotations[self.l_counter] = item
-
- def out(self, string):
- self.queue += string
-
- def cook(self):
- if self.queue:
- queue = self.queue
- self.queue = ''
- self.write(
- "%s(%s)" %
- (self.symbols.write, repr(queue)))
-
- def write(self, string):
- if isinstance(string, unicode) and self.encoding:
- string = string.encode(self.encoding)
-
- self.l_counter += len(string.split('\n'))-1
-
- self.cook()
- BufferIO.write(self,
- self.indentation_string * self.indentation + string + '\n')
-
- def getvalue(self):
- self.cook()
- return BufferIO.getvalue(self)
-
- def escape(self, variable):
- self.write("if '&' in %s:" % variable)
- self.indent()
- self.write("%s = %s.replace('&', '&')" % (variable, variable))
- self.outdent()
- self.write("if '<' in %s:" % variable)
- self.indent()
- self.write("%s = %s.replace('<', '<')" % (variable, variable))
- self.outdent()
- self.write("if '>' in %s:" % variable)
- self.indent()
- self.write("%s = %s.replace('>', '>')" % (variable, variable))
- self.outdent()
- self.write("if '\"' in %s:" % variable)
- self.indent()
- self.write("%s = %s.replace('\"', '"')" % (variable, variable))
- self.outdent()
-
- def begin(self, clauses):
- if isinstance(clauses, (list, tuple)):
- for clause in clauses:
- self.begin(clause)
- else:
- clauses.begin(self)
-
- def end(self, clauses):
- if isinstance(clauses, (list, tuple)):
- for clause in reversed(clauses):
- self.end(clause)
- else:
- clauses.end(self)
Deleted: z3c.pt/trunk/src/z3c/pt/genshi.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/genshi.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/genshi.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,237 +0,0 @@
-import translation
-import expressions
-import utils
-import config
-import etree
-
-class GenshiElement(translation.Element, translation.VariableInterpolation):
- """Genshi element.
-
- Implements the Genshi subset of the attribute template language.
- """
-
- class node(translation.Node):
- @property
- def omit(self):
- if self.element.py_strip is not None:
- return self.element.py_strip or True
- if self.element.meta_omit is not None:
- return self.element.meta_omit or True
- if self.element.py_replace or self.element.meta_replace:
- return True
- if self.element.xi_href:
- return True
-
- @property
- def define(self):
- return self.element.py_with
-
- @property
- def condition(self):
- return self.element.py_if
-
- @property
- def repeat(self):
- return self.element.py_for
-
- @property
- def content(self):
- return self.element.py_content or self.element.py_replace or \
- self.element.meta_replace
-
- @property
- def skip(self):
- return bool(self.content)
-
- @property
- def dict_attributes(self):
- return self.element.py_attrs
-
- @property
- def dynamic_attributes(self):
- return self.element.meta_attributes
-
- @property
- def static_attributes(self):
- return utils.get_attributes_from_namespace(
- self.element, config.XHTML_NS)
-
- @property
- def macro(self):
- return self.element.py_def
-
- @property
- def cdata(self):
- return self.element.meta_cdata
-
- @property
- def include(self):
- return self.element.xi_href
-
- @property
- def format(self):
- return self.element.xi_parse
-
- node = property(node)
-
- def update(self):
- # Step 1: Convert py:choose, py:when, py:otherwise into
- # tal:define, tal:condition
- stream = self.stream
- choose_expression = self._pull_attribute(utils.py_attr('choose'))
- if choose_expression is not None:
- choose_variable = stream.save()
-
- if choose_expression:
- self._add_define(choose_variable, choose_expression)
-
- # select all elements that have the "py:when" controller,
- # unless a "py:choose" expression sits in-between
- variables = []
- for element in self.xpath(
- './*[@py:when]|.//*[not(@py:choose)]/*[@py:when]',
- namespaces={'py': config.PY_NS}):
-
- expression = element._pull_attribute(utils.py_attr('when'))
- variable = stream.save()
- variables.append(variable)
-
- # add definition to ancestor
- self._add_define(variable, expression)
-
- # add condition to element
- if choose_expression:
- expression = "python: %s == %s" % (
- choose_variable, variable)
- else:
- expression = "python: %s" % variable
-
- element.attrib[utils.py_attr('if')] = expression
-
- # process any "py:otherwise"-controllers
- for element in self.xpath(
- './*[@py:otherwise]|.//*[not(@py:choose)]/*[@py:otherwise]',
- namespaces={'py': config.PY_NS}):
- if choose_expression:
- expression = "python: %s not in %s" % (
- choose_variable, repr(tuple(variables)))
- else:
- expression = "python: not(%s)" % " or ".join(variables)
-
- element.attrib[utils.py_attr('if')] = expression
-
- # Step 2: Process "py:match" macros
- for element in self:
- if getattr(element, 'py_match', None) is None:
- continue
-
- nsmap = element.nsmap.copy()
-
- # default namespace is not allowed in XPath
- nsmap['xmlns'] = nsmap[None]
- del nsmap[None]
-
- # define macro
- name = stream.save()
- element.attrib[utils.py_attr('def')] = "%s(select)" % name
-
- matches = self.getroottree().getroot().xpath(
- element.py_match, namespaces=nsmap)
- for match in matches:
- # save reference to bound xpath-function
- select = stream.save()
- stream.selectors[select] = match.xpath
-
- # replace matched element with macro
- expression = "%s(%s)" % (name, select)
- match.attrib[utils.py_attr('replace')] = expression
-
- # save select-variable as element attribute
- match.attrib[utils.meta_attr('select')] = select
-
- # Step 3: Variable interpolation
- translation.VariableInterpolation.update(self)
-
- def _add_define(self, variable, expression):
- name = utils.py_attr('with')
- define = "%s=%s; " % (variable, expression)
-
- if name in self.attrib:
- self.attrib[name] += define
- else:
- self.attrib[name] = define
-
- def _pull_attribute(self, name, default=None):
- attrib = self.attrib
- if name in attrib:
- value = attrib[name]
- del attrib[name]
- return value
- return default
-
-class XHTMLElement(GenshiElement):
- """XHTML namespace element."""
-
- py_if = utils.attribute(
- utils.py_attr('if'), lambda p: p.expression)
- py_for = utils.attribute(
- utils.py_attr('for'), lambda p: p.definition)
- py_with = utils.attribute(utils.py_attr('with'),
- lambda p: expressions.python_translation.definitions)
- py_choose = utils.attribute(
- utils.py_attr('choose'), lambda p: p.expression)
- py_when = utils.attribute(
- utils.py_attr('when'), lambda p: p.expression)
- py_match = utils.attribute(
- utils.py_attr('match'))
- py_def = utils.attribute(
- utils.py_attr('def'), lambda p: p.method)
- py_attrs = utils.attribute(
- utils.py_attr('attrs'), lambda p: p.expression)
- py_content = utils.attribute(
- utils.py_attr('content'), lambda p: p.output)
- py_replace = utils.attribute(
- utils.py_attr('replace'), lambda p: p.output)
- py_strip = utils.attribute(
- utils.py_attr('strip'), lambda p: p.expression)
- xi_href = None
- xi_parse = None
-
-class MetaElement(XHTMLElement, translation.MetaElement):
- pass
-
-class PyElement(XHTMLElement):
- py_strip = utils.attribute("strip", lambda p: p.expression, u"")
-
-class PyIfElement(PyElement):
- py_if = utils.attribute("test", lambda p: p.expression)
-
-class PyForElement(PyElement):
- py_for = utils.attribute("each", lambda p: p.definition)
-
-class PyWithElement(PyElement):
- py_with = utils.attribute(
- "vars", lambda p: expressions.python_translation.definitions)
-
-class PyDefElement(PyElement):
- py_def = utils.attribute("function", lambda p: p.method)
-
-class PyMatchElement(PyElement):
- py_match = utils.attribute("path")
-
-class XiIncludeElement(XHTMLElement):
- xi_href = utils.attribute(
- "href", lambda p: expressions.StringTranslation(p).expression)
- xi_parse = utils.attribute("parse", default="xml")
-
-class GenshiParser(etree.Parser):
- """ The parser implementation for Genshi templates """
- element_mapping = {
- config.XHTML_NS: {None: XHTMLElement},
- config.META_NS: {None: MetaElement},
- config.XI_NS: {'include': XiIncludeElement},
- config.PY_NS: {'if': PyIfElement,
- 'for': PyForElement,
- 'def': PyDefElement,
- 'with': PyWithElement,
- 'match': PyMatchElement}}
Deleted: z3c.pt/trunk/src/z3c/pt/genshi.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/genshi.txt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/genshi.txt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,439 +0,0 @@
-Genshi
-======
-
- >>> from z3c.pt.testing import render_genshi
-
-py:if
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <div py:if="False">
- ... <p>Bar</p>
- ... </div>
- ... <div py:if="True">
- ... <p>Foo</p>
- ... </div>
- ... <py:if test="False">
- ... <b>Bar</b>
- ... </py:if>
- ... <py:if test="True">
- ... <b>Foo</b>
- ... </py:if>
- ... </div>""")
- <div>
- <div>
- <p>Foo</p>
- </div>
- <BLANKLINE>
- <b>Foo</b>
- <BLANKLINE>
- </div>
-
-py:choose, py:when, py:otherwise
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <div py:choose="">
- ... <span py:when="0 == 1">0</span>
- ... <span py:when="1 == 1">1</span>
- ... <div>
- ... <span py:when="2 == 2">2</span>
- ... <span py:when="2 == 3">3</span>
- ... <div py:choose="1">
- ... <b py:when="1">3</b>
- ... <b py:when="2">4</b>
- ... </div>
- ... </div>
- ... <span py:otherwise="">3</span>
- ... <div py:choose="1">
- ... <span py:when="0">1</span>
- ... <span py:otherwise="">1</span>
- ... </div>
- ... <div py:choose="">
- ... <span py:when="0 == 1">1</span>
- ... <span py:otherwise="">2</span>
- ... </div>
- ... </div>
- ... </div>""")
- <div>
- <div>
- <span>1</span>
- <div>
- <span>2</span>
- <div>
- <b>3</b>
- </div>
- </div>
- <div>
- <span>1</span>
- </div>
- <div>
- <span>2</span>
- </div>
- </div>
- </div>
-
-py:for
-
- >>> print render_genshi("""\
- ... <ul xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <li py:for="item in range(3)">${item}</li>
- ... <py:for each="item in range(3, 5)">
- ... <li>${item}</li>
- ... </py:for>
- ... </ul>""")
- <ul>
- <li>0</li>
- <li>1</li>
- <li>2</li>
- <li>3</li>
- <li>4</li>
- </ul>
-
-py:def
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <p py:def="greeting(name)" class="greeting">
- ... Hello, ${name}!
- ... </p>
- ... ${greeting('world')}
- ... ${greeting('everyone else')}
- ... <py:def function="goodbye(name)">
- ... <p class="goodbye">Goodbye, ${name}!</p>
- ... </py:def>
- ... ${goodbye('world')}
- ... ${goodbye('everyone')}
- ... </div>""")
- <div>
- <p class="greeting">
- Hello, world!
- </p>
- <BLANKLINE>
- <p class="greeting">
- Hello, everyone else!
- </p>
- <BLANKLINE>
- <BLANKLINE>
- <p class="goodbye">Goodbye, world!</p>
- <BLANKLINE>
- <BLANKLINE>
- <BLANKLINE>
- <p class="goodbye">Goodbye, everyone!</p>
- <BLANKLINE>
- <BLANKLINE>
- </div>
-
-py:with
-
- >>> def quote():
- ... return dict(author=u"Some name", quote=u"Some random quote")
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <span py:with="x=2; y=7; z=x+10">${x} ${y} ${z}</span>
- ... <py:with vars="x=4; y=3; z=x+5">${x} ${y} ${z}</py:with>
- ... <blockquote py:with="q=quote()">
- ... "${q["quote"]} <em>${q["author"]}</em>
- ... </blockquote>
- ... </div>""", quote=quote)
- <div>
- <span>2 7 12</span>
- 4 3 9
- <blockquote>
- "Some random quote <em>Some name</em>
- </blockquote>
- </div>
-
-
-py:attrs
-
- >>> print render_genshi("""\
- ... <ul xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <li class="expand" py:attrs="{'class': 'collapse'}">Bar</li>
- ... <li class="expand" py:attrs="d">Bar</li>
- ... </ul>""", d=dict({'class': u'\u1234'}))
- <ul>
- <li class="collapse">Bar</li>
- <li class="á´">Bar</li>
- </ul>
-
-py:content, py:replace
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <span py:content="'Hello, world!'" />
- ... <span py:replace="'Goodbye, world!'" />
- ... </div>""")
- <div>
- <span>Hello, world!</span>
- Goodbye, world!
- </div>
-
-py:strip
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <span py:strip="True"><b>foo</b></span>
- ... </div>""")
- <div>
- <b>foo</b>
- </div>
-
-py:match
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <span py:match=".//xmlns:greeting">
- ... Hello, ${select('@name')[0]}!
- ... </span>
- ... <py:match path=".//xmlns:farewell">
- ... <span>Goodbye, ${select('@name')[0]}!</span>
- ... </py:match>
- ... <greeting name="dude" />
- ... <farewell name="dude" />
- ... </div>""")
- <div>
- <span>
- Hello, dude!
- </span>
- <BLANKLINE>
- <BLANKLINE>
- <span>Goodbye, dude!</span>
- <BLANKLINE>
- <BLANKLINE>
- </div>
-
-:: Genshi variable interpolation (${<exp>} notation)
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <span>inter${'pol' + 'ati'}on</span>is ${int('test') | 'convenient'}!
- ... <span>${'a'}${'b'}${'c'} ${'d'}</span>
- ... <span py:with="hello='Hello'" class="${hello} World!" />
- ... <span class="my-${'class'} item${'Last'}" />
- ... <a href="${ltr.href}" class="${ltr.iscurrent}">${ltr.letter}</a>
- ... <span style="position: ${'abs'}olute"
- ... class="my-${int('test') | 'class'} item${'Last'}" />
- ... </div>""", ltr={'letter': 'A', 'href': '?title=A', 'iscurrent': 'current'})
- <div>
- <span>interpolation</span>is convenient!
- <span>abc d</span>
- <span class="Hello World!" />
- <span class="my-class itemLast" />
- <a href="?title=A" class="current">A</a>
- <span style="position: absolute" class="my-class itemLast" />
- </div>
-
-:: Simple variable names do not need { .. }. From `py:with specs`_.
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <span py:with="y=7; z=x+10">$x $y $z</span>
- ... </div>""", x=42)
- <div>
- <span>42 7 52</span>
- </div>
-
-:: Genshi variable interpolation and unicode values
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... <img alt="${'La Peña'}" />
- ... <img alt="Hello ${'La Peña'}" />
- ... <img alt="La Peña, oh ${'La Peña'}" />
- ... ${unicode('La Pe\xc3\xb1a', 'utf-8').encode('utf-8')}
- ... <img alt="${unicode('La Pe\xc3\xb1a', 'utf-8').encode('utf-8')}" />
- ... <img alt="Hello ${unicode('La Pe\xc3\xb1a', 'utf-8').encode('utf-8')}!" />
- ... </div>""", encoding='utf-8')
- <div>
- <img alt="La Peña" />
- <img alt="Hello La Peña" />
- <img alt="La Peña, oh La Peña" />
- La Peña
- <img alt="La Peña" />
- <img alt="Hello La Peña!" />
- </div>
-
-:: Unicode combined with attribute expansion
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... <img alt="La Peña" />
- ... <img alt="${alt}" />
- ... </div>""", alt=unicode("La Pe\xc3\xb1a", 'utf-8'))
- <div>
- <img alt="La Peña" />
- <img alt="La Peña" />
- </div>
-
-:: Variables containing quotes
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... <strong>"${quote}"</strong>
- ... </div>""", quote="Hello, World!")
- <div>
- <strong>"Hello, World!"</strong>
- </div>
-
-:: Variables containing markup
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... ${message}
- ... </div>""", message="Hello, <em>World</em>!")
- <div>
- Hello, <em>World</em>!
- </div>
-
-:: Variable expansion must preserve XML validity
-
- >>> from z3c.pt import config
- >>> config.VALIDATION = True
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... ${message}
- ... </div>""", message="Hello, <em>World!")
- Traceback (most recent call last):
- ...
- ValidationError: Insertion of 'Hello, <em>World!' is not allowed.
-
- >>> config.VALIDATION = False
-
-:: Unless we are in a CDATA block
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... /* <![CDATA[ */
- ... ${message}
- ... /* ]]> */
- ... </div>""", message="Hello, <em>World!")
- <div>
- /* <![CDATA[ */
- Hello, <em>World!
- /* ]]> */
- </div>
-
-:: HTML comments
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <!-- a comment -->
- ... <!-- a multi-
- ... line comment -->
- ... <!-- a comment with an ${'expression'} -->
- ... </div>""")
- <div>
- <!-- a comment -->
- <!-- a multi-
- line comment -->
- <!-- a comment with an expression -->
- </div>
-
-:: z3c.pt used to forget to output the ]; after the for loop
-
- >>> print render_genshi("""\
- ... <script xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/"
- ... type="text/javascript">
- ... var brands = [
- ... <py:for each="brand in []">
- ... { value : "${brand['id']}", "title" : "${brand['title']}" },
- ... </py:for>
- ... ];
- ... </script>""")
- <script type="text/javascript">
- var brands = [
- ];
- </script>
-
-:: Strange looping behaviour
-
- >>> brands=[dict(id=1, title="One"),
- ... dict(id=2, title="Two"),
- ... dict(id=3, title="Three")]
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <script type="text/javascript">
- ... var brands = [
- ... <py:for each="brand in brands">
- ... { value : "${brand['id']}", title : "${brand['title']}" },
- ... </py:for>
- ... ];
- ...
- ... $(document.ready(function() {
- ... alert("Hello, World");
- ... });
- ... </script>
- ... </div>""", brands=brands)
- <div>
- <script type="text/javascript">
- var brands = [
- { value : "1", title : "One" },
- { value : "2", title : "Two" },
- { value : "3", title : "Three" },
- ];
- <BLANKLINE>
- $(document.ready(function() {
- alert("Hello, World");
- });
- </script>
- </div>
-
-:: Very basic recursing
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <ul py:def="rendermenu(menu)" py:if="menu">
- ... ${rendermenu([])}
- ... </ul>
- ... </div>""")
- <div>
- </div>
-
-:: Slightly more complex recursive function calls
-
- >>> print render_genshi("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <ul py:def="rendermenu(menu)">
- ... <li py:for="entry in menu"
- ... py:attrs="{'class' : entry['current'] and 'current' or None}">
- ... <a py:attrs="dict(href=entry['url'])"
- ... py:content="entry['title']">Merken</a>
- ... ${rendermenu(entry.get('children', []))}
- ... </li>
- ... </ul>
- ... ${rendermenu(menu)}
- ... </div>""", menu=[dict(title=u"Menu entry", url="/test", current=True)])
- <div>
- <ul>
- <li class="current">
- <a href="/test">Menu entry</a>
- <ul>
- <BLANKLINE>
- </ul>
- <BLANKLINE>
- </li>
- <BLANKLINE>
- </ul>
- <BLANKLINE>
- </div>
-
-.. _py:with specs: http://genshi.edgewall.org/wiki/Documentation/0.4.x/xml-templates.html#py-with
-
Deleted: z3c.pt/trunk/src/z3c/pt/interfaces.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/interfaces.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/interfaces.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,138 +0,0 @@
-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
-
- Not to be confused with a Python iterator.
- """
-
- def next():
- """Advance to the next value in the iteration, if possible
-
- Return a true value if it was possible to advance and return
- a false value otherwise.
- """
-
-class ITALESIterator(ITALIterator):
- """TAL Iterator provided by TALES
-
- Values of this iterator are assigned to items in the repeat namespace.
-
- For example, with a TAL statement like: tal:repeat="item items",
- an iterator will be assigned to "repeat/item". The iterator
- provides a number of handy methods useful in writing TAL loops.
-
- The results are undefined of calling any of the methods except
- 'length' before the first iteration.
- """
-
- def index():
- """Return the position (starting with "0") within the iteration
- """
-
- def number():
- """Return the position (starting with "1") within the iteration
- """
-
- def even():
- """Return whether the current position is even
- """
-
- def odd():
- """Return whether the current position is odd
- """
-
- def parity():
- """Return 'odd' or 'even' depending on the position's parity
-
- Useful for assigning CSS class names to table rows.
- """
-
- def start():
- """Return whether the current position is the first position
- """
-
- def end():
- """Return whether the current position is the last position
- """
-
- def letter():
- """Return the position (starting with "a") within the iteration
- """
-
- def Letter():
- """Return the position (starting with "A") within the iteration
- """
-
- def roman():
- """Return the position (starting with "i") within the iteration
- """
-
- def Roman():
- """Return the position (starting with "I") within the iteration
- """
-
- def item():
- """Return the item at the current position
- """
-
- def length():
- """Return the length of the sequence
-
- Note that this may fail if the TAL iterator was created on a Python
- iterator.
- """
Modified: z3c.pt/trunk/src/z3c/pt/loader.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/loader.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/loader.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,51 +1,15 @@
import errno
import os.path
+
from z3c.pt.pagetemplate import PageTemplateFile
from z3c.pt.texttemplate import TextTemplateFile
-def cache(func):
- def load(self, *args):
- template = self.registry.get(args)
- if template is None:
- self.registry[args] = template = func(self, *args)
- return template
- return load
-
-class TemplateLoader(object):
- """Template loader tool. To load templates using relative
- filenames, pass a sequence of paths (or a single path) as
- ``search_path``; if ``auto_reload`` is set, templates will be
- reloaded when modified."""
+from chameleon.core import loader
- def __init__(self, search_path=None, auto_reload=False, parser=None):
- if search_path is None:
- search_path = []
- if isinstance(search_path, basestring):
- search_path = [search_path]
- self.search_path = search_path
- self.auto_reload = auto_reload
- self.parser = parser
- self.registry = {}
-
- @cache
- def _load(self, filename, klass):
- if os.path.isabs(filename):
- return klass(filename, self.parser)
-
- for path in self.search_path:
- path = os.path.join(path, filename)
- try:
- return klass(
- path, self.parser, auto_reload=self.auto_reload)
- except OSError, e:
- if e.errno != errno.ENOENT:
- raise
-
- raise ValueError("Can not find template %s" % filename)
-
+class TemplateLoader(loader.TemplateLoader):
def load_page(self, filename):
- return self._load(filename, PageTemplateFile)
+ return self.load(filename, PageTemplateFile)
def load_text(self, filename):
- return self._load(filename, TextTemplateFile)
+ return self.load(filename, TextTemplateFile)
Modified: z3c.pt/trunk/src/z3c/pt/pagetemplate.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/pagetemplate.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/pagetemplate.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,62 +1,16 @@
-import zope.i18n
-
-import template
-import config
-import zpt
-import sys
import os
+import sys
-def prepare_language_support(**kwargs):
- target_language = kwargs.get('target_language')
+from chameleon.zpt.template import PageTemplate
+from chameleon.zpt.template import PageTemplateFile
+from chameleon.zpt.language import Parser
- if config.DISABLE_I18N:
- if target_language:
- del kwargs['target_language']
- return
-
- if not target_language:
- context = kwargs.get(config.SYMBOLS.i18n_context)
- target_language = zope.i18n.negotiate(context)
-
- if target_language:
- kwargs['target_language'] = target_language
-
-class PageTemplate(template.BaseTemplate):
- __doc__ = template.BaseTemplate.__doc__ # for Sphinx autodoc
-
- default_parser = zpt.ZopePageTemplateParser()
-
- def __init__(self, body, parser=None, format=None, doctype=None):
- if parser is None:
- parser = self.default_parser
- super(PageTemplate, self).__init__(body, parser, format, doctype)
-
- def render(self, **kwargs):
- prepare_language_support(**kwargs)
- return super(PageTemplate, self).render(**kwargs)
-
-class PageTemplateFile(template.BaseTemplateFile):
- __doc__ = template.BaseTemplateFile.__doc__ # for Sphinx autodoc
-
- default_parser = zpt.ZopePageTemplateParser()
-
- def __init__(self, filename, parser=None, format=None,
- doctype=None, **kwargs):
- if parser is None:
- parser = self.default_parser
- super(PageTemplateFile, self).__init__(filename, parser, format,
- doctype, **kwargs)
-
- def render(self, **kwargs):
- prepare_language_support(**kwargs)
- return super(PageTemplateFile, self).render(**kwargs)
-
class ZopePageTemplate(PageTemplate):
- default_parser = zpt.ZopePageTemplateParser(default_expression='path')
+ default_parser = Parser(default_expression='path')
class ZopePageTemplateFile(PageTemplateFile):
- default_parser = zpt.ZopePageTemplateParser(default_expression='path')
-
+ default_parser = Parser(default_expression='path')
+
class ViewPageTemplate(property):
"""Template class suitable for use with a Zope browser view; the
variables ``view``, ``context`` and ``request`` variables are
@@ -65,8 +19,10 @@
dictionary. Note that the default expression type for this class
is 'path' (standard Zope traversal)."""
+ template_class = ZopePageTemplate
+
def __init__(self, body, **kwargs):
- self.template = ZopePageTemplate(body, **kwargs)
+ self.template = self.template_class(body, **kwargs)
property.__init__(self, self.bind)
def bind(self, view, request=None, macro=None, global_scope=True):
@@ -95,6 +51,8 @@
class ViewPageTemplateFile(ViewPageTemplate):
"""If ``filename`` is a relative path, the module path of the
class where the instance is used to get an absolute path."""
+
+ template_class = ZopePageTemplateFile
def __init__(self, filename, path=None, content_type=None, **kwargs):
if path is not None:
@@ -117,7 +75,7 @@
filename = path + os.sep + filename
- self.template = ZopePageTemplateFile(filename, **kwargs)
+ self.template = self.template_class(filename, **kwargs)
property.__init__(self, self.bind)
def __call__(self, view, **kwargs):
Deleted: z3c.pt/trunk/src/z3c/pt/template.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/template.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/template.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,195 +0,0 @@
-import os
-import config
-import doctypes
-import filecache
-import translation
-
-class BaseTemplate(object):
- """Constructs a template object using the template language
- defined by ``parser`` (``ZopePageTemplateParser`` or
- ``GenshiParser`` as of this writing). Must be passed an input
- string as ``body``. The ``format`` parameter supports values 'xml'
- and 'text'. Pass a value for ``encoding`` if you need to allow
- strings that are not unicode or plain ASCII."""
-
- compilers = {
- 'xml': translation.Compiler,
- 'text': translation.Compiler.from_text}
-
- format = 'xml'
- implicit_doctype = doctypes.xhtml
- explicit_doctype = None
-
- def __init__(self, body, parser, format=None, doctype=None, encoding=None):
- self.body = body
- self.parser = parser
- self.signature = hash(body)
- self.registry = {}
- self.encoding = encoding
-
- if format is not None:
- self.format = format
-
- if doctype is not None:
- self.explicit_doctype = doctype
-
- @property
- def macros(self):
- return Macros(self.render_macro)
-
- @property
- def compiler(self):
- return self.compilers[self.format](
- self.body, self.parser,
- implicit_doctype=self.implicit_doctype,
- explicit_doctype=self.explicit_doctype,
- encoding=self.encoding)
-
- def cook(self, **kwargs):
- return self.compiler(**kwargs)
-
- def cook_check(self, parameters, **kwargs):
- key = tuple(parameters), \
- tuple(item for item in kwargs.iteritems()), \
- self.signature, self.explicit_doctype
- template = self.registry.get(key, None)
- if template is None:
- template = self.cook(parameters=parameters, **kwargs)
- self.registry[key] = template
- return template
-
- def render(self, **kwargs):
- template = self.cook_check(parameters=kwargs)
- return template.render(**kwargs)
-
- def render_macro(self, macro, global_scope=False, parameters={}):
- template = self.cook_check(
- parameters=parameters, macro=macro, global_scope=global_scope)
- return template.render(**parameters)
-
- def render_xinclude(self, **kwargs):
- return self.render_macro("", parameters=kwargs)
-
- def __repr__(self):
- return u"<%s %d>" % (self.__class__.__name__, id(self))
-
- def __call__(self, **kwargs):
- return self.render(**kwargs)
-
-class BaseTemplateFile(BaseTemplate):
- """Constructs a template object using the template language
- defined by ``parser``. Must be passed an absolute (or
- current-working-directory-relative) filename as ``filename``. If
- ``auto_reload`` is true, each time the template is rendered, it
- will be recompiled if it has been changed since the last
- rendering."""
-
- global_registry = {}
-
- def __init__(self, filename, parser, format=None, doctype=None,
- auto_reload=False):
- BaseTemplate.__init__(
- self, None, parser, format=format, doctype=doctype)
-
- self.auto_reload = auto_reload
- self.filename = filename = os.path.abspath(
- os.path.normpath(os.path.expanduser(filename)))
-
- # make sure file exists
- os.lstat(filename)
-
- # read template
- self.read()
-
- # persist template registry on disk
- if config.DISK_CACHE:
- self.registry = self.global_registry.setdefault(
- filename, filecache.TemplateCache(filename))
-
- self.xincludes = XIncludes(
- self.global_registry, os.path.dirname(filename), self.clone)
-
- def clone(self, filename, format=None):
- cls = type(self)
- return cls(
- filename, self.parser, format=format,
- doctype=self.explicit_doctype, auto_reload=self.auto_reload)
-
- def _get_filename(self):
- return getattr(self, '_filename', None)
-
- def _set_filename(self, filename):
- self._filename = filename
- self._v_last_read = False
-
- filename = property(_get_filename, _set_filename)
-
- def read(self):
- filename = self.filename
- mtime = self.mtime()
- fd = open(filename, 'r')
- self.body = body = fd.read()
- fd.close()
- self.signature = filename, mtime
- self._v_last_read = mtime
-
- def cook(self, **kwargs):
- template = self.compiler(**kwargs)
-
- if config.DEBUG_MODE:
- filename = "%s.py" % self.filename
- f = open(filename, 'w')
- f.write(template.source)
- f.close()
-
- return template
-
- def cook_check(self, **kwargs):
- if self.auto_reload and self._v_last_read != self.mtime():
- self.read()
-
- return BaseTemplate.cook_check(self, **kwargs)
-
- def render(self, **kwargs):
- kwargs[config.SYMBOLS.xincludes] = self.xincludes
- return super(BaseTemplateFile, self).render(**kwargs)
-
- def mtime(self):
- try:
- return os.path.getmtime(self.filename)
- except (IOError, OSError):
- return 0
-
- def __repr__(self):
- return u"<%s %s>" % (self.__class__.__name__, self.filename)
-
-class XIncludes(object):
- """Dynamic XInclude registry providing a ``get``-method that will
- resolve a filename to a template instance. Format must be
- explicitly provided."""
-
- def __init__(self, registry, relpath, factory):
- self.registry = registry
- self.relpath = relpath
- self.factory = factory
-
- def get(self, filename, format):
- if not os.path.isabs(filename):
- filename = os.path.join(self.relpath, filename)
- template = self.registry.get(filename)
- if template is not None:
- return template
- return self.factory(filename, format=format)
-
-class Macro(object):
- def __init__(self, render):
- self.render = render
-
-class Macros(object):
- def __init__(self, render_macro):
- self.render = render_macro
-
- def __getitem__(self, name):
- def render(**kwargs):
- return self.render(name, parameters=kwargs)
- return Macro(render)
Deleted: z3c.pt/trunk/src/z3c/pt/template.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/template.txt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/template.txt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,288 +0,0 @@
-Template classes
-================
-
-This section demonstrates the high-level template classes.
-
-z3c.pt.pagetemplate.PageTemplate
---------------------------------
-
- >>> from z3c.pt.pagetemplate import PageTemplate
- >>> from z3c.pt.testing import mock_parser
-
- >>> print PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... Hello World!
- ... </div>""")()
- <div>
- Hello World!
- </div>
-
-z3c.pt.pagetemplate.PageTemplateFile
-------------------------------------
-
- >>> from z3c.pt.pagetemplate import PageTemplateFile
- >>> from z3c.pt import tests
- >>> path = tests.__path__[0]
- >>> t = PageTemplateFile(path+'/helloworld.pt')
- >>> print t()
- <div>
- Hello World!
- </div>
-
- >>> import os
- >>> t.filename.startswith(os.sep)
- True
-
-z3c.pt.pagetemplate.ViewPageTemplate
-------------------------------------
-
- >>> from z3c.pt.pagetemplate import ViewPageTemplate
-
- >>> class ViewPageTemplateView(object):
- ... __call__ = ViewPageTemplate(
- ... open(path+'/view.pt').read())
- ... request = u'request'
- ... context = u'context'
-
- >>> view = ViewPageTemplateView()
-
- >>> print view(test=u'test')
- <div>
- <span><ViewPageTemplateView object at ...></span>
- <span>context</span>
- <span>request</span>
- <span>test</span>
- </div>
-
-z3c.pt.pagetemplate.ViewPageTemplateFile
-----------------------------------------
-
- >>> from z3c.pt.pagetemplate import ViewPageTemplateFile
-
- >>> class ViewPageTemplateView(object):
- ... __call__ = ViewPageTemplateFile(path+'/view.pt')
- ... request = u'request'
- ... context = u'context'
-
- >>> view = ViewPageTemplateView()
-
- >>> print view(test=u'test')
- <div>
- <span><ViewPageTemplateView object at ...></span>
- <span>context</span>
- <span>request</span>
- <span>test</span>
- </div>
-
-z3c.pt.texttemplate.ViewTextTemplate
-------------------------------------
-
- >>> from z3c.pt.texttemplate import ViewTextTemplate
-
- >>> class ViewTextTemplateView(object):
- ... __call__ = ViewTextTemplate(open(path+'/view.css').read())
- ... request = u'request'
- ... context = u'context'
-
- >>> view = ViewTextTemplateView()
-
- >>> print view(color=u'#ccc')
- #region {
- background: #ccc;
- }
-
-z3c.pt.texttemplate.ViewTextTemplateFile
-----------------------------------------
-
- >>> from z3c.pt.texttemplate import ViewTextTemplateFile
-
- >>> class ViewTextTemplateView(object):
- ... __call__ = ViewTextTemplateFile(path+'/view.css')
- ... request = u'request'
- ... context = u'context'
-
- >>> view = ViewTextTemplateView()
-
- >>> print view(color=u'#ccc')
- #region {
- background: #ccc;
- }
-
-Compiler integration
---------------------
-
-Certain constructs require close collaboration between the template
-compiler and the page template classes.
-
-py:match integration
-
- >>> from z3c.pt.genshi import GenshiParser
-
- >>> print PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:py="http://genshi.edgewall.org/">
- ... <py:match path=".//xmlns:greeting">Hello ${select('@name')[0]}!</py:match>
- ... <greeting name="World" />
- ... </div>
- ... """, parser=GenshiParser())()
- <div>
- Hello World!
- <BLANKLINE>
- </div>
-
-metal:define-macro, metal:use-macro
-
- >>> template1 = PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal"
- ... xmlns:metal="http://xml.zope.org/namespaces/metal">
- ... <div metal:define-macro="greeting">
- ... Hello, ${name}!
- ... <span tal:define="global name 'earth'">
- ... Hello, ${name}!
- ... </span>
- ... Hello, ${name}!
- ... </div>
- ... </div>""")
-
- >>> template2 = PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal"
- ... xmlns:metal="http://xml.zope.org/namespaces/metal">
- ... <div tal:define="name 'world'">
- ... <div metal:use-macro="template1.macros['greeting']" />
- ... Hello, ${name}!
- ... </div>
- ... Hello, ${name}!
- ... </div>""")
-
- >>> print template2(template1=template1)
- <div>
- <div>
- <div>
- Hello, world!
- <span>
- Hello, earth!
- </span>
- Hello, earth!
- </div>
- <BLANKLINE>
- Hello, world!
- </div>
- Hello, earth!
- </div>
-
-metal:define-macro, metal:use-macro, metal:define-slot, metal:fill-slot
-
- >>> main = PageTemplate("""\
- ... <html xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal"
- ... xmlns:metal="http://xml.zope.org/namespaces/metal"
- ... metal:define-macro="master">
- ... <div metal:define-slot="content">
- ... I will be replaced
- ... </div>
- ... </html>""")
-
- >>> content = PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal"
- ... xmlns:metal="http://xml.zope.org/namespaces/metal"
- ... metal:use-macro="main.macros['master']">
- ... <div metal:fill-slot="content">
- ... I replace you.
- ... </div>
- ... </div>""")
-
- >>> print content(main=main)
- <html>
- <div>
- I replace you.
- </div>
- </html>
-
-xi:include
-
- >>> from z3c.pt.template import BaseTemplateFile
- >>> template1 = BaseTemplateFile(path+"/xinclude1.pt", mock_parser)
- >>> print template1()
- <div>
- <div>
- <span>Hello, world!</span>
- </div>
- </div>
-
-:: XInclude in Genshi
-
-When using XInclude-statements in Genshi, macro-definitions are
-carried over from the included template. This is demonstrated below.
-
- >>> template2 = BaseTemplateFile(path+"/xinclude3.pt", GenshiParser())
- >>> print template2()
- <div>
- <BLANKLINE>
- <BLANKLINE>
- <p class="greeting">
- Hello, world!
- </p>
- <BLANKLINE>
- </div>
-
-Before we proceed, we reduce and restore the underlying byte-code
-template.
-
- >>> from cPickle import dumps, loads
- >>> for registry in (template1.registry, template2.registry):
- ... for key, bct in registry.items():
- ... registry[key] = loads(dumps(bct))
-
- >>> print template2()
- <div>
- <BLANKLINE>
- <BLANKLINE>
- <p class="greeting">
- Hello, world!
- </p>
- <BLANKLINE>
- </div>
-
-
-Error handling
---------------
-
-When an exception is raised which does not expose a bug in the TAL
-translation machinery, we expect the exception to contain the part of
-the template source that caused the exception.
-
-Exception while evaluating expression:
-
- >>> PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <span tal:content="range()" />
- ... </div>""").render()
- Traceback (most recent call last):
- ...
- TypeError: range expected at least 1 arguments, got 0
-
-Exception while evaluating definition:
-
- >>> PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <span tal:define="dummy range()" />
- ... </div>""").render()
- Traceback (most recent call last):
- ...
- TypeError: range expected at least 1 arguments, got 0
-
-Exception while evaluating interpolation:
-
- >>> PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <span>${range()}</span>
- ... </div>""").render()
- Traceback (most recent call last):
- ...
- TypeError: range expected at least 1 arguments, got 0
Deleted: z3c.pt/trunk/src/z3c/pt/testing.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/testing.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/testing.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,136 +0,0 @@
-import translation
-import template
-import generation
-import expressions
-import doctypes
-import etree
-import config
-import utils
-
-import zpt
-import genshi
-
-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(string):
- return expressions.python_translation.expression(string)
-
-def setup_stream(encoding=None):
- class symbols(translation.Node.symbols):
- out = '_out'
- write = '_write'
-
- out = StringIO()
- write = out.write
- stream = generation.CodeIO(symbols, encoding=encoding)
- return out, write, stream
-
-def compile_xhtml(body, **kwargs):
- compiler = TestCompiler(
- body, mock_parser, implicit_doctype=doctypes.xhtml)
- return compiler(parameters=sorted(kwargs.keys()))
-
-def render_xhtml(body, **kwargs):
- template = compile_xhtml(body, **kwargs)
- return template.render(**kwargs)
-
-def render_text(body, **kwargs):
- compiler = TestCompiler.from_text(
- body, mock_parser, implicit_doctype=doctypes.xhtml)
- template = compiler(parameters=sorted(kwargs.keys()))
- return template.render(**kwargs)
-
-def render_zpt(body, **kwargs):
- compiler = TestCompiler(
- body, zpt.ZopePageTemplateParser(), implicit_doctype=doctypes.xhtml)
- template = compiler(parameters=sorted(kwargs.keys()))
- return template.render(**kwargs)
-
-def render_genshi(body, encoding=None, **kwargs):
- compiler = TestCompiler(
- body, genshi.GenshiParser(),
- encoding=encoding, implicit_doctype=doctypes.xhtml)
- template = compiler(parameters=sorted(kwargs.keys()))
- kwargs.update(template.selectors)
- return template.render(**kwargs)
-
-class MockTemplate(object):
- def __init__(self, body, parser):
- self.body = body
- self.parser = parser
-
- @property
- def macros(self):
- def render(name, parameters={}):
- compiler = TestCompiler(self.body, self.parser)
- template = compiler(macro=name, parameters=parameters)
- return template.render(**parameters)
- return template.Macros(render)
-
-class MockElement(translation.Element, translation.VariableInterpolation):
- translator = expressions.python_translation
-
- def update(self):
- translation.VariableInterpolation.update(self)
-
- class node(translation.Node):
- def __getattr__(self, name):
- return None
-
- @property
- def static_attributes(self):
- return utils.get_attributes_from_namespace(
- self.element, config.XHTML_NS)
-
- @property
- def omit(self):
- if self.element.meta_omit is not None:
- return self.element.meta_omit or True
- if self.content:
- return True
- if self.include:
- return True
-
- @property
- def content(self):
- return self.element.meta_replace
-
- @property
- def cdata(self):
- return self.element.meta_cdata
-
- @property
- def include(self):
- return self.element.xi_href
-
- @property
- def format(self):
- return self.element.xi_parse
-
- node = property(node)
-
- xi_href = None
- xi_parse = None
-
-class MockMetaElement(MockElement, translation.MetaElement):
- pass
-
-class MockXiElement(MockElement):
- xi_href = utils.attribute(
- "href", lambda p: expressions.StringTranslation(p).expression)
- xi_parse = utils.attribute("parse", default="xml")
-
-class MockParser(etree.Parser):
- element_mapping = {
- config.XHTML_NS: {None: MockElement},
- config.META_NS: {None: MockMetaElement},
- config.XI_NS: {None: MockXiElement}}
-
-mock_parser = MockParser()
Modified: z3c.pt/trunk/src/z3c/pt/tests/test_doctests.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/test_doctests.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/tests/test_doctests.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -6,26 +6,20 @@
import zope.component.testing
import zope.configuration.xmlconfig
+import z3c.pt
-import z3c.pt.config
+from chameleon.core import config
def setUp(suite):
zope.component.testing.setUp(suite)
zope.configuration.xmlconfig.XMLConfig('configure.zcml', z3c.pt)()
def test_suite():
- filesuites = ('zpt.txt', 'genshi.txt', 'template.txt',
- 'i18n.txt', 'codegen.txt', 'translation.txt')
- testsuites = ('z3c.pt.translation', 'z3c.pt.clauses', 'z3c.pt.expressions')
+ filesuites = 'README.txt',
- z3c.pt.config.DISK_CACHE = False
+ config.DISK_CACHE = False
return unittest.TestSuite(
- [zope.testing.doctest.DocTestSuite(
- doctest, optionflags=OPTIONFLAGS,
- setUp=setUp, tearDown=zope.component.testing.tearDown) \
- for doctest in testsuites] +
-
[zope.testing.doctest.DocFileSuite(
doctest, optionflags=OPTIONFLAGS,
setUp=setUp, tearDown=zope.component.testing.tearDown,
Deleted: z3c.pt/trunk/src/z3c/pt/tests/test_edgecases.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/test_edgecases.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/tests/test_edgecases.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,204 +0,0 @@
-import unittest
-
-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 z3c.pt
- from zope.configuration import xmlconfig
- xmlconfig.file('configure.zcml', z3c.pt)
- from z3c.pt.pagetemplate import PageTemplate
- 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 = PageTemplate(body)
- self.assertEqual(norm(t.render(foo=u'foo')), norm(expected))
-
-class TestUnicodeAttributeLiteral(unittest.TestCase, PlacelessSetup):
- def setUp(self):
- PlacelessSetup.setUp(self)
-
- def tearDown(self):
- PlacelessSetup.tearDown(self)
-
- def test_it(self):
- import z3c.pt
- from zope.configuration import xmlconfig
- xmlconfig.file('configure.zcml', z3c.pt)
- from z3c.pt.pagetemplate import PageTemplate
- 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">
- <div id="${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">
- <div id="\xa9"/>
- </html>"""
- t = PageTemplate(body)
- c = unicode('\xc2\xa9', 'utf-8')
- self.assertEqual(norm(t.render(foo=c)), norm(expected))
-
- def test_torture(self):
- import z3c.pt
- from z3c.pt.genshi import GenshiParser
- from zope.configuration import xmlconfig
- xmlconfig.file('configure.zcml', z3c.pt)
- from z3c.pt.pagetemplate import PageTemplate
- 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"
- xmlns:py="http://genshi.edgewall.org/">
- <title>\xa9</title>
- <div id="${foo}" py:attrs="dict(label=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">
- <title>\xa9</title>
- <div label="\xa9" id="\xa9"/>
- </html>"""
- t = PageTemplate(body, parser=GenshiParser())
- c = unicode('\xc2\xa9', 'utf-8')
- self.assertEqual(norm(t.render(foo=c)), norm(expected))
-
-class TestZCMLActionsPickleable(unittest.TestCase, PlacelessSetup):
- # see also
- # http://groups.google.com/group/z3c_pt/browse_thread/thread/bd0cc94b5fd40ae0?hl=en
- def setUp(self):
- PlacelessSetup.setUp(self)
-
- def tearDown(self):
- PlacelessSetup.tearDown(self)
-
- def test_registry_actions_can_be_pickled_and_unpickled(self):
- from z3c import pt as package
- from zope.configuration import config
- from zope.configuration import xmlconfig
- context = config.ConfigurationMachine()
- xmlconfig.registerCommonDirectives(context)
- context.package = package
- xmlconfig.include(context, 'configure.zcml', package)
- context.execute_actions(clear=False)
- actions = context.actions
- import pickle
- dumped = pickle.dumps(actions, -1)
- new = pickle.loads(dumped)
- self.assertEqual(len(actions), len(new))
-
-class TestExplicitDoctypes(unittest.TestCase, PlacelessSetup):
- def setUp(self):
- PlacelessSetup.setUp(self)
-
- def tearDown(self):
- PlacelessSetup.tearDown(self)
-
- def test_doctype_declared_in_constructor_adds_doctype(self):
- import z3c.pt
- from zope.configuration import xmlconfig
- xmlconfig.file('configure.zcml', z3c.pt)
- from z3c.pt.pagetemplate import PageTemplate
- from z3c.pt import doctypes
- body = u"""\
- <html xmlns="http://www.w3.org/1999/xhtml">
- </html>
- """
- expected = u"""\
- <!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- </html>"""
- t = PageTemplate(body, doctype=doctypes.xhtml_strict)
- self.assertEqual(norm(t.render()), norm(expected))
-
- def test_doctype_declared_in_constructor_overrides_template_doctype(self):
- import z3c.pt
- from zope.configuration import xmlconfig
- xmlconfig.file('configure.zcml', z3c.pt)
- from z3c.pt.pagetemplate import PageTemplate
- from z3c.pt import doctypes
- 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">
- </html>
- """
- expected = u"""\
- <!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- </html>"""
- t = PageTemplate(body, doctype=doctypes.xhtml_strict)
- self.assertEqual(norm(t.render()), norm(expected))
-
- def test_doctype_assigned_to_instance_overrides_constructor_doctype(self):
- import z3c.pt
- from zope.configuration import xmlconfig
- xmlconfig.file('configure.zcml', z3c.pt)
- from z3c.pt.pagetemplate import PageTemplate
- from z3c.pt import doctypes
- 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">
- </html>
- """
- expected = u"""\
- <!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- </html>"""
- t = PageTemplate(body, doctype=doctypes.html)
- t.doctype = doctypes.html
- self.assertEqual(norm(t.render()), norm(expected))
-
- def test_no_doctype_overrides_parsed_doctype(self):
- import z3c.pt
- from zope.configuration import xmlconfig
- xmlconfig.file('configure.zcml', z3c.pt)
- from z3c.pt.pagetemplate import PageTemplate
- from z3c.pt import doctypes
- 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">
- </html>
- """
- expected = u"""\
- <html xmlns="http://www.w3.org/1999/xhtml">
- </html>"""
- t = PageTemplate(body, doctype=doctypes.no_doctype)
- self.assertEqual(norm(t.render()), norm(expected))
-
-def norm(s):
- return s.replace(' ', '').replace('\n', '')
-
-def test_suite():
- import sys
- return unittest.findTestCases(sys.modules[__name__])
Modified: z3c.pt/trunk/src/z3c/pt/tests/view.pt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/view.pt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/tests/view.pt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,6 +1,6 @@
<div xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal">
- <span tal:content="nocall: view" />
+ <span tal:content="view" />
<span tal:content="context" />
<span tal:content="request" />
<span tal:content="options/test" />
Deleted: z3c.pt/trunk/src/z3c/pt/tests/xinclude1.pt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/xinclude1.pt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/tests/xinclude1.pt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,4 +0,0 @@
-<div xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <xi:include href="xinclude${1+1}.pt" />
-</div>
Deleted: z3c.pt/trunk/src/z3c/pt/tests/xinclude2.pt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/xinclude2.pt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/tests/xinclude2.pt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,3 +0,0 @@
-<div xmlns="http://www.w3.org/1999/xhtml">
- <span>Hello, world!</span>
-</div>
Deleted: z3c.pt/trunk/src/z3c/pt/tests/xinclude3.pt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/xinclude3.pt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/tests/xinclude3.pt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,6 +0,0 @@
-<div xmlns="http://www.w3.org/1999/xhtml"
- xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <xi:include href="xinclude${4}.pt" />
- ${greeting('world')}
-</div>
Deleted: z3c.pt/trunk/src/z3c/pt/tests/xinclude4.pt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/xinclude4.pt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/tests/xinclude4.pt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,7 +0,0 @@
-<div xmlns="http://www.w3.org/1999/xhtml"
- xmlns:py="http://genshi.edgewall.org/"
- py:strip="">
- <p py:def="greeting(name)" class="greeting">
- Hello, ${name}!
- </p>
-</div>
Modified: z3c.pt/trunk/src/z3c/pt/texttemplate.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/texttemplate.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/texttemplate.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,5 +1,4 @@
import pagetemplate
-import translation
class TextTemplate(pagetemplate.PageTemplate):
__doc__ = pagetemplate.PageTemplate.__doc__ # for Sphinx autodoc
@@ -9,21 +8,10 @@
__doc__ = pagetemplate.PageTemplateFile.__doc__ # for Sphinx autodoc
format = 'text'
-class ViewTextTemplate(property):
- def __init__(self, body):
- self.template = TextTemplate(body)
- property.__init__(self, self.render)
-
- def render(self, view):
- def template(**kwargs):
- return self.template.render(view=view,
- context=view.context,
- request=view.request,
- _context=view.request,
- options=kwargs)
- return template
-
-class ViewTextTemplateFile(ViewTextTemplate):
- def __init__(self, filename):
- self.template = TextTemplateFile(filename)
- property.__init__(self, self.render)
+class ViewTextTemplate(pagetemplate.ViewPageTemplate):
+ __doc__ = pagetemplate.ViewPageTemplate.__doc__ # for Sphinx autodoc
+ template_class = TextTemplate
+
+class ViewTextTemplateFile(pagetemplate.ViewPageTemplateFile):
+ __doc__ = pagetemplate.ViewPageTemplateFile.__doc__ # for Sphinx autodoc
+ template_class = TextTemplateFile
Deleted: z3c.pt/trunk/src/z3c/pt/transformer.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/transformer.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/transformer.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,235 +0,0 @@
-from compiler import ast
-
-class ASTTransformer(object):
- """General purpose base class for AST transformations.
-
- Every visitor method can be overridden to return an AST node that has been
- altered or replaced in some way.
- """
-
- def visit(self, node):
- if node is None:
- return None
- if type(node) is tuple:
- return tuple([self.visit(n) for n in node])
- visitor = getattr(self, 'visit%s' % node.__class__.__name__,
- self._visitDefault)
- return visitor(node)
-
- def _clone(self, node, *args):
- lineno = getattr(node, 'lineno', None)
- node = node.__class__(*args)
- if lineno is not None:
- node.lineno = lineno
- if isinstance(node, (ast.Class, ast.Function, ast.GenExpr, ast.Lambda)):
- node.filename = '<string>' # workaround for bug in pycodegen
- return node
-
- def _visitDefault(self, node):
- return node
-
- def visitExpression(self, node):
- return self._clone(node, self.visit(node.node))
-
- def visitModule(self, node):
- return self._clone(node, node.doc, self.visit(node.node))
-
- def visitStmt(self, node):
- return self._clone(node, [self.visit(x) for x in node.nodes])
-
- # Classes, Functions & Accessors
-
- def visitCallFunc(self, node):
- return self._clone(node, self.visit(node.node),
- [self.visit(x) for x in node.args],
- node.star_args and self.visit(node.star_args) or None,
- node.dstar_args and self.visit(node.dstar_args) or None
- )
-
- def visitClass(self, node):
- return self._clone(node, node.name, [self.visit(x) for x in node.bases],
- node.doc, self.visit(node.code)
- )
-
- def visitFunction(self, node):
- args = []
- if hasattr(node, 'decorators'):
- args.append(self.visit(node.decorators))
- return self._clone(node, *args + [
- node.name,
- node.argnames,
- [self.visit(x) for x in node.defaults],
- node.flags,
- node.doc,
- self.visit(node.code)
- ])
-
- def visitGetattr(self, node):
- return self._clone(node, self.visit(node.expr), node.attrname)
-
- def visitLambda(self, node):
- node = self._clone(node, node.argnames,
- [self.visit(x) for x in node.defaults], node.flags,
- self.visit(node.code)
- )
- return node
-
- def visitSubscript(self, node):
- return self._clone(node, self.visit(node.expr), node.flags,
- [self.visit(x) for x in node.subs]
- )
-
- # Statements
-
- def visitAssert(self, node):
- return self._clone(node, self.visit(node.test), self.visit(node.fail))
-
- def visitAssign(self, node):
- return self._clone(node, [self.visit(x) for x in node.nodes],
- self.visit(node.expr)
- )
-
- def visitAssAttr(self, node):
- return self._clone(node, self.visit(node.expr), node.attrname,
- node.flags
- )
-
- def visitAugAssign(self, node):
- return self._clone(node, self.visit(node.node), node.op,
- self.visit(node.expr)
- )
-
- def visitDecorators(self, node):
- return self._clone(node, [self.visit(x) for x in node.nodes])
-
- def visitExec(self, node):
- return self._clone(node, self.visit(node.expr), self.visit(node.locals),
- self.visit(node.globals)
- )
-
- def visitFor(self, node):
- return self._clone(node, self.visit(node.assign), self.visit(node.list),
- self.visit(node.body), self.visit(node.else_)
- )
-
- def visitIf(self, node):
- return self._clone(node, [self.visit(x) for x in node.tests],
- self.visit(node.else_)
- )
-
- def _visitPrint(self, node):
- return self._clone(node, [self.visit(x) for x in node.nodes],
- self.visit(node.dest)
- )
- visitPrint = visitPrintnl = _visitPrint
-
- def visitRaise(self, node):
- return self._clone(node, self.visit(node.expr1), self.visit(node.expr2),
- self.visit(node.expr3)
- )
-
- def visitReturn(self, node):
- return self._clone(node, self.visit(node.value))
-
- def visitTryExcept(self, node):
- return self._clone(node, self.visit(node.body), self.visit(node.handlers),
- self.visit(node.else_)
- )
-
- def visitTryFinally(self, node):
- return self._clone(node, self.visit(node.body), self.visit(node.final))
-
- def visitWhile(self, node):
- return self._clone(node, self.visit(node.test), self.visit(node.body),
- self.visit(node.else_)
- )
-
- def visitWith(self, node):
- return self._clone(node, self.visit(node.expr),
- [self.visit(x) for x in node.vars], self.visit(node.body)
- )
-
- def visitYield(self, node):
- return self._clone(node, self.visit(node.value))
-
- # Operators
-
- def _visitBoolOp(self, node):
- return self._clone(node, [self.visit(x) for x in node.nodes])
- visitAnd = visitOr = visitBitand = visitBitor = visitBitxor = _visitBoolOp
- visitAssTuple = visitAssList = _visitBoolOp
-
- def _visitBinOp(self, node):
- return self._clone(node,
- (self.visit(node.left), self.visit(node.right))
- )
- visitAdd = visitSub = _visitBinOp
- visitDiv = visitFloorDiv = visitMod = visitMul = visitPower = _visitBinOp
- visitLeftShift = visitRightShift = _visitBinOp
-
- def visitCompare(self, node):
- return self._clone(node, self.visit(node.expr),
- [(op, self.visit(n)) for op, n in node.ops]
- )
-
- def _visitUnaryOp(self, node):
- return self._clone(node, self.visit(node.expr))
- visitUnaryAdd = visitUnarySub = visitNot = visitInvert = _visitUnaryOp
- visitBackquote = visitDiscard = _visitUnaryOp
-
- def visitIfExp(self, node):
- return self._clone(node, self.visit(node.test), self.visit(node.then),
- self.visit(node.else_)
- )
-
- # Identifiers, Literals and Comprehensions
-
- def visitDict(self, node):
- return self._clone(node,
- [(self.visit(k), self.visit(v)) for k, v in node.items]
- )
-
- def visitGenExpr(self, node):
- return self._clone(node, self.visit(node.code))
-
- def visitGenExprFor(self, node):
- return self._clone(node, self.visit(node.assign), self.visit(node.iter),
- [self.visit(x) for x in node.ifs]
- )
-
- def visitGenExprIf(self, node):
- return self._clone(node, self.visit(node.test))
-
- def visitGenExprInner(self, node):
- quals = [self.visit(x) for x in node.quals]
- return self._clone(node, self.visit(node.expr), quals)
-
- def visitKeyword(self, node):
- return self._clone(node, node.name, self.visit(node.expr))
-
- def visitList(self, node):
- return self._clone(node, [self.visit(n) for n in node.nodes])
-
- def visitListComp(self, node):
- quals = [self.visit(x) for x in node.quals]
- return self._clone(node, self.visit(node.expr), quals)
-
- def visitListCompFor(self, node):
- return self._clone(node, self.visit(node.assign), self.visit(node.list),
- [self.visit(x) for x in node.ifs]
- )
-
- def visitListCompIf(self, node):
- return self._clone(node, self.visit(node.test))
-
- def visitSlice(self, node):
- return self._clone(node, self.visit(node.expr), node.flags,
- node.lower and self.visit(node.lower) or None,
- node.upper and self.visit(node.upper) or None
- )
-
- def visitSliceobj(self, node):
- return self._clone(node, [self.visit(x) for x in node.nodes])
-
- def visitTuple(self, node):
- return self._clone(node, [self.visit(n) for n in node.nodes])
Deleted: z3c.pt/trunk/src/z3c/pt/translation.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/translation.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/translation.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,770 +0,0 @@
-from StringIO import StringIO
-
-import generation
-import expressions
-import codegen
-import clauses
-import doctypes
-import itertools
-import types
-import utils
-import config
-import etree
-import marshal
-import htmlentitydefs
-
-class Node(object):
- """Element translation class.
-
- This class implements the translation node for an element in the
- template document tree.
-
- It's used internally by the translation machinery.
- """
-
- symbols = config.SYMBOLS
-
- translate = None
- translation_name = None
- translation_domain = None
- translated_attributes = None
- skip = None
- cdata = None
- omit = None
- define = None
- macro = None
- use_macro = None
- define_macro = None
- fill_slot = None
- define_slot = None
- condition = None
- repeat = None
- content = None
- include = None
- format = None
- dict_attributes = None
- static_attributes = utils.emptydict()
- dynamic_attributes = utils.emptydict()
-
- def __init__(self, element):
- self.element = element
-
- @property
- def stream(self):
- return self.element.stream
-
- def update(self):
- self.element.update()
-
- def begin(self):
- self.stream.scope.append(set())
- self.stream.begin(self.serialize())
-
- def end(self):
- self.stream.end(self.serialize())
- self.stream.scope.pop()
-
- def body(self):
- if not self.skip:
- for element in self.element:
- element.node.update()
-
- for element in self.element:
- element.node.visit()
-
- def visit(self):
- assert self.stream is not None, "Must use ``start`` method."
-
- for element in self.element:
- if not isinstance(element, Element):
- self.wrap_literal(element)
-
- self.update()
- self.begin()
- self.body()
- self.end()
-
- def serialize(self):
- """Serialize element into clause-statements."""
-
- _ = []
-
- # i18n domain
- if self.translation_domain is not None:
- _.append(clauses.Define(
- self.symbols.domain, types.value(repr(self.translation_domain))))
-
- # variable definitions
- if self.define is not None:
- for declaration, expression in self.define:
- if declaration.global_scope:
- _.append(clauses.Define(
- declaration, expression, self.symbols.scope))
- else:
- _.append(clauses.Define(declaration, expression))
-
- # macro method
- macro = self.macro
- if macro is not None:
- _.append(clauses.Method(
- macro.name, macro.args))
-
- # tag tail (deferred)
- tail = self.element.tail
- if tail and not self.fill_slot:
- if isinstance(tail, unicode) and self.stream.encoding:
- tail = tail.encode(self.stream.encoding)
- _.append(clauses.Out(tail, defer=True))
-
- # condition
- if self.condition is not None:
- _.append(clauses.Condition(self.condition))
-
- # repeat
- if self.repeat is not None:
- variables, expression = self.repeat
- if len(variables) != 1:
- raise ValueError(
- "Cannot unpack more than one variable in a "
- "repeat statement.")
- _.append(clauses.Repeat(variables[0], expression))
-
- content = self.content
-
- # macro slot definition
- if self.define_slot:
- # check if slot has been filled
- variable = self.symbols.slot + self.define_slot
- if variable in itertools.chain(*self.stream.scope):
- content = types.value(variable)
-
- # set dynamic content flag
- dynamic = content or self.translate is not None
-
- # static attributes are at the bottom of the food chain
- attributes = utils.odict()
- attributes.update(self.static_attributes)
-
- # dynamic attributes
- dynamic_attrs = self.dynamic_attributes or ()
- dynamic_attr_names = []
-
- for variables, expression in dynamic_attrs:
- if len(variables) != 1:
- raise ValueError("Tuple definitions in assignment clause "
- "is not supported.")
-
- variable = variables[0]
- attributes[variable] = expression
- dynamic_attr_names.append(variable)
-
- # translated attributes
- translated_attributes = self.translated_attributes or ()
- for variable, msgid in translated_attributes:
- if msgid:
- if variable in dynamic_attr_names:
- raise ValueError(
- "Message id not allowed in conjunction with "
- "a dynamic attribute.")
-
- value = types.value('"%s"' % msgid)
-
- if variable in attributes:
- default = '"%s"' % attributes[variable]
- expression = self.translate_expression(value, default=default)
- else:
- expression = self.translate_expression(value)
- else:
- if variable in dynamic_attr_names or variable in attributes:
- text = '"%s"' % attributes[variable]
- expression = self.translate_expression(text)
- else:
- raise ValueError("Must be either static or dynamic "
- "attribute when no message id "
- "is supplied.")
-
- attributes[variable] = expression
-
- # tag
- text = self.element.text
- if self.omit is not True:
- selfclosing = text is None and not dynamic and len(self.element) == 0
- tag = clauses.Tag(
- self.element.tag, attributes,
- expression=self.dict_attributes, selfclosing=selfclosing,
- cdata=self.cdata is not None)
- if self.omit:
- _.append(clauses.Condition(
- types.value("not (%s)" % self.omit), [tag], finalize=False))
- else:
- _.append(tag)
-
- # tag text (if we're not replacing tag body)
- if text and not dynamic and not self.use_macro:
- if isinstance(text, unicode) and self.stream.encoding:
- text = text.encode(self.stream.encoding)
- _.append(clauses.Out(text))
-
- # dynamic content
- if content:
- msgid = self.translate
- if msgid is not None:
- if msgid:
- raise ValueError(
- "Can't use message id with dynamic content translation.")
-
- _.append(clauses.Assign(content, self.symbols.tmp))
- content = self.translate_expression(
- types.value(self.symbols.tmp))
-
- _.append(clauses.Write(content))
-
- # include
- elif self.include:
- # compute macro function arguments and create argument string
- arguments = ", ".join(
- ("%s=%s" % (arg, arg) for arg in \
- itertools.chain(*self.stream.scope)))
-
- # XInclude's are similar to METAL macros, except the macro
- # is always defined as the entire template.
-
- # first we compute the filename expression and write it to
- # an internal variable
- _.append(clauses.Assign(self.include, self.symbols.include))
-
- # call template
- _.append(clauses.Write(
- types.template(
- "%%(xincludes)s.get(%%(include)s, %s).render_xinclude(%s)" % \
- (repr(self.format), arguments))))
-
- # use macro
- elif self.use_macro:
- # for each fill-slot element, create a new output stream
- # and save value in a temporary variable
- kwargs = []
- for element in self.element.xpath(
- './/*[@metal:fill-slot] | .//metal:*[@fill-slot]',
- namespaces={'metal': config.METAL_NS}):
- if element.node.fill_slot is None:
- # XXX this should not be necessary, but the above
- # xpath expression finds non-"metal:fill-slot"
- # nodes somehow on my system; this is perhaps due
- # to a bug in the libxml2 version I'm using; we
- # work around it by just skipping the element.
- # (chrism)
- continue
-
- variable = self.symbols.slot+element.node.fill_slot
- kwargs.append((variable, variable))
-
- subclauses = []
- subclauses.append(clauses.Define(
- types.declaration((self.symbols.out, self.symbols.write)),
- types.template('%(init)s.initialize_stream()')))
- subclauses.append(clauses.Visit(element.node))
- subclauses.append(clauses.Assign(
- types.template('%(out)s.getvalue()'), variable))
- _.append(clauses.Group(subclauses))
-
- _.append(clauses.Assign(self.use_macro, self.symbols.metal))
-
- # compute macro function arguments and create argument string
- if 'xmlns' in self.element.attrib:
- kwargs.append(('include_ns_attribute', repr(True)))
-
- arguments = ", ".join(
- tuple("%s=%s" % (arg, arg) for arg in \
- itertools.chain(*self.stream.scope))+
- tuple("%s=%s" % kwarg for kwarg in kwargs))
-
- _.append(clauses.Write(
- types.value("%s.render(%s)" % (self.symbols.metal, arguments))))
-
- # translate body
- elif self.translate is not None:
- msgid = self.translate
- if not msgid:
- msgid = self.create_msgid()
-
- # for each named block, create a new output stream
- # and use the value in the translation mapping dict
- elements = [e for e in self.element if e.node.translation_name]
-
- if elements:
- mapping = self.symbols.mapping
- _.append(clauses.Assign(types.value('{}'), mapping))
- else:
- mapping = 'None'
-
- for element in elements:
- name = element.node.translation_name
-
- subclauses = []
- subclauses.append(clauses.Define(
- types.declaration((self.symbols.out, self.symbols.write)),
- types.template('%(init)s.initialize_stream()')))
- subclauses.append(clauses.Visit(element.node))
- subclauses.append(clauses.Assign(
- types.template('%(out)s.getvalue()'),
- "%s['%s']" % (mapping, name)))
-
- _.append(clauses.Group(subclauses))
-
- _.append(clauses.Assign(
- self.translate_expression(
- types.value(repr(msgid)), mapping=mapping,
- default=self.symbols.marker), self.symbols.result))
-
- # write translation to output if successful, otherwise
- # fallback to default rendition;
- result = types.value(self.symbols.result)
- result.symbol_mapping[self.symbols.marker] = generation.marker
- condition = types.template('%(result)s is not %(marker)s')
- _.append(clauses.Condition(condition,
- [clauses.UnicodeWrite(result)]))
-
- subclauses = []
- if self.element.text:
- subclauses.append(clauses.Out(self.element.text.encode('utf-8')))
- for element in self.element:
- name = element.node.translation_name
- if name:
- value = types.value("%s['%s']" % (mapping, name))
- subclauses.append(clauses.Write(value))
- else:
- subclauses.append(clauses.Out(element.tostring()))
- if subclauses:
- _.append(clauses.Else(subclauses))
-
- return _
-
- def wrap_literal(self, element):
- index = self.element.index(element)
-
- t = self.element.makeelement(utils.meta_attr('literal'))
- t.attrib['omit-tag'] = ''
- t.tail = element.tail
- t.text = unicode(element)
- for child in element.getchildren():
- t.append(child)
- self.element.remove(element)
- self.element.insert(index, t)
- t.update()
-
- def create_msgid(self):
- """Create an i18n msgid from the tag contents."""
-
- out = StringIO(self.element.text)
- for element in self.element:
- name = element.node.translation_name
- if name:
- out.write("${%s}" % name)
- out.write(element.tail)
- else:
- out.write(element.tostring())
-
- msgid = out.getvalue().strip()
- msgid = msgid.replace(' ', ' ').replace('\n', '')
-
- return msgid
-
- def translate_expression(self, value, mapping=None, default=None):
- format = "%%(translate)s(%s, domain=%%(domain)s, mapping=%s, " \
- "target_language=%%(language)s, default=%s)"
- template = types.template(
- format % (value, mapping, default))
-
- # add translate-method to symbol mapping
- translate = generation.fast_translate
- template.symbol_mapping[config.SYMBOLS.translate] = translate
-
- return template
-
-class Element(etree.ElementBase):
- """Template element class.
-
- To start translation at this element, use the ``start`` method,
- providing a code stream object.
- """
-
- translator = expressions.python_translation
-
- class node(Node):
- @property
- def omit(self):
- if self.element.meta_omit is not None:
- return self.element.meta_omit or True
- if self.element.meta_replace:
- return True
-
- @property
- def content(self):
- return self.element.meta_replace
-
- node = property(node)
-
- def start(self, stream):
- self._stream = stream
- self.node.visit()
-
- def update(self):
- pass
-
- @property
- def stream(self):
- while self is not None:
- try:
- return self._stream
- except AttributeError:
- self = self.getparent()
-
- raise ValueError("Can't locate stream object.")
-
- meta_cdata = utils.attribute(
- utils.meta_attr('cdata'))
-
- meta_omit = utils.attribute(
- utils.meta_attr('omit-tag'))
-
- meta_attributes = utils.attribute(
- utils.meta_attr('attributes'), lambda p: p.definitions)
-
- meta_replace = utils.attribute(
- utils.meta_attr('replace'), lambda p: p.output)
-
-class MetaElement(Element):
- meta_cdata = utils.attribute('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.
-
- >>> class MockElement(NativeAttributePrefixSupport):
- ... nsmap = {'prefix1': 'ns1'}
- ... prefix = 'prefix1'
- ... attrib = {'{ns1}attr1': '1', 'attr2': '2', '{ns2}attr3': '3'}
-
- >>> 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
- itself. ``explicit_doctype`` may be used to explicitly set a
- doctype regardless of what the template defines."""
-
- doctype = None
- implicit_doctype = ""
-
- def __init__(self, body, parser, implicit_doctype=None,
- explicit_doctype=None, encoding=None):
- # documents without a document type declaration are augmented
- # with default namespace declarations and proper XML entity
- # definitions; this represents a 'convention' over
- # 'configuration' approach to template documents
- no_doctype_declaration = '<!DOCTYPE' not in body
-
- # add default namespace declaration if no explicit document
- # type has been set
- if implicit_doctype and explicit_doctype is None and \
- no_doctype_declaration:
- body = """\
- <meta:declare-ns
- xmlns="%s" xmlns:tal="%s" xmlns:metal="%s" xmlns:i18n="%s"
- xmlns:py="%s" xmlns:xinclude="%s" xmlns:meta="%s"
- >%s</meta:declare-ns>""" % (
- config.XHTML_NS, config.TAL_NS,
- config.METAL_NS, config.I18N_NS,
- config.PY_NS, config.XI_NS, config.META_NS,
- body)
-
- # prepend the implicit doctype to the document source and add
- # entity definitions
- if implicit_doctype and no_doctype_declaration:
- entities = "".join((
- '<!ENTITY %s "&#%s;">' % (name, text) for (name, text) in \
- htmlentitydefs.name2codepoint.items()))
-
- implicit_doctype = implicit_doctype[:-1] + ' [ %s ]>' % entities
- self.implicit_doctype = implicit_doctype
- body = implicit_doctype + "\n" + body
-
- # parse document
- self.root, parsed_doctype = parser.parse(body)
-
- # explicit document type has priority
- if explicit_doctype is not None:
- self.doctype = explicit_doctype
- elif parsed_doctype and not no_doctype_declaration:
- self.doctype = parsed_doctype
-
- self.parser = parser
-
- if utils.coerces_gracefully(encoding):
- self.encoding = None
- else:
- self.encoding = encoding
-
- @classmethod
- def from_text(cls, body, parser, **kwargs):
- compiler = Compiler(
- "<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')] = ""
- return compiler
-
- def __call__(self, macro=None, global_scope=True, parameters=()):
- if not isinstance(self.root, Element):
- raise ValueError(
- "Must define valid namespace for tag: '%s.'" % self.root.tag)
-
- # if macro is non-trivial, start compilation at the element
- # where the macro is defined
- if macro:
- elements = self.root.xpath(
- 'descendant-or-self::*[@metal:define-macro="%s"] |'
- 'descendant-or-self::metal:*[@define-macro="%s"]' % (macro, macro),
- namespaces={'metal': config.METAL_NS})
-
- if not elements:
- raise ValueError("Macro not found: %s." % macro)
-
- self.root = element = elements[0]
-
- # remove attribute from tag
- if element.nsmap[element.prefix] == config.METAL_NS:
- del element.attrib['define-macro']
- else:
- del element.attrib[utils.metal_attr('define-macro')]
-
- if macro is None or 'include_ns_attribute' in parameters:
- # add namespace attribute to
- namespace = self.root.tag.split('}')[0][1:]
- self.root.attrib['xmlns'] = namespace
-
- if global_scope:
- wrapper = generation.template_wrapper
- else:
- wrapper = generation.macro_wrapper
-
- # initialize code stream object
- stream = generation.CodeIO(
- self.root.node.symbols, encoding=self.encoding,
- indentation=1, indentation_string="\t")
-
- # initialize variable scope
- stream.scope.append(set(
- (stream.symbols.out, stream.symbols.write, stream.symbols.scope) + \
- tuple(parameters)))
-
- # output doctype if any
- if self.doctype and not macro:
- doctype = self.doctype + '\n'
- if self.encoding:
- doctype = doctype.encode(self.encoding)
- out = clauses.Out(doctype)
- stream.scope.append(set())
- stream.begin([out])
- stream.end([out])
- stream.scope.pop()
-
- # start generation
- self.root.start(stream)
- body = stream.getvalue()
-
- # remove namespace declaration
- if 'xmlns' in self.root.attrib:
- del self.root.attrib['xmlns']
-
- # prepare args
- ignore = 'target_language',
- args = ', '.join((param for param in parameters if param not in ignore))
- if args:
- args += ', '
-
- # prepare kwargs
- kwargs = ', '.join("%s=None" % param for param in parameters)
- if kwargs:
- kwargs += ', '
-
- # prepare selectors
- extra = ''
- for selector in stream.selectors:
- extra += '%s=None, ' % selector
-
- # wrap generated Python-code in function definition
- mapping = dict(
- args=args, kwargs=kwargs, extra=extra, body=body)
- mapping.update(stream.symbols.__dict__)
- source = wrapper % mapping
-
- # serialize document
- xmldoc = self.implicit_doctype + "\n" + self.root.tostring()
-
- return ByteCodeTemplate(
- source, stream.symbol_mapping,
- xmldoc, self.parser, self.root)
-
-class ByteCodeTemplate(object):
- """Template compiled to byte-code."""
-
- def __init__(self, source, symbols, xmldoc, parser, tree):
- # compile code
- suite = codegen.Suite(source, globals=symbols)
- suite._globals.update(symbols)
-
- # execute code
- _locals = {}
- exec suite.code in suite._globals, _locals
-
- # keep state
- self.func = _locals['render']
- self.source = source
- self.symbols = symbols
- self.xmldoc = xmldoc
- self.parser = parser
- self.tree = tree
-
- def __reduce__(self):
- reconstructor, (cls, base, state), kwargs = \
- GhostedByteCodeTemplate(self).__reduce__()
- return reconstructor, (ByteCodeTemplate, base, state), kwargs
-
- def __setstate__(self, state):
- self.__dict__.update(GhostedByteCodeTemplate.rebuild(state))
-
- def __repr__(self):
- return '<%s parser="%s">' % \
- (type(self).__name__, str(type(self.parser)).split("'")[1])
-
- def render(self, *args, **kwargs):
- kwargs.update(self.selectors)
- return self.func(generation, *args, **kwargs)
-
- @property
- def selectors(self):
- selectors = getattr(self, '_selectors', None)
- if selectors is not None:
- return selectors
-
- self._selectors = selectors = {}
- for element in self.tree.xpath(
- './/*[@meta:select]', namespaces={'meta': config.META_NS}):
- name = element.attrib[utils.meta_attr('select')]
- selectors[name] = element.xpath
-
- return selectors
-
-class GhostedByteCodeTemplate(object):
- suite = codegen.Suite("def render(): pass")
-
- def __init__(self, template):
- self.code = marshal.dumps(template.func.func_code)
- self.defaults = len(template.func.func_defaults or ())
- self.symbols = template.symbols
- self.source = template.source
- self.xmldoc = template.xmldoc
- self.parser = template.parser
-
- @classmethod
- def rebuild(cls, state):
- symbols = state['symbols']
- source = state['source']
- xmldoc = state['xmldoc']
- parser = state['parser']
- tree, doctype = parser.parse(xmldoc)
-
- _locals = {}
- _globals = symbols.copy()
- _globals.update(cls.suite._globals)
- exec cls.suite.code in _globals, _locals
-
- func = _locals['render']
- func.func_defaults = ((None,)*state['defaults']) or None
- func.func_code = marshal.loads(state['code'])
-
- return dict(
- func=func,
- symbols=symbols,
- source=source,
- xmldoc=xmldoc,
- parser=parser,
- tree=tree)
-
-
Deleted: z3c.pt/trunk/src/z3c/pt/translation.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/translation.txt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/translation.txt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,197 +0,0 @@
-Translation
-===========
-
-This document contains functional template tests.
-
- >>> from z3c.pt.testing import render_xhtml
-
-XHTML
------
-
-:: Plain HTML document
-
- >>> print render_xhtml("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... Hello World!
- ... </div>""")
- <div>
- Hello World!
- </div>
-
-:: Setting DOCTYPE
-
- >>> print render_xhtml("""\
- ... <!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">
- ... Hello World!
- ... </html>""")
- <!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">
- Hello World!
- </html>
-
-:: Unicode
-
- >>> print render_xhtml("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... La Peña
- ... <img alt="La Peña" />
- ... </div>""")
- <div>
- La Peña
- <img alt="La Peña" />
- </div>
-
-:: CDATA blocks
- >>> print render_xhtml("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... /* <![CDATA[ */
- ... This is protected
- ... /* ]]> */
- ... <span>Not protected</span> <![CDATA[ This is protected ]]>
- ... </div>""")
- <div>
- /* <![CDATA[ */
- This is protected
- /* ]]> */
- <span>Not protected</span> <![CDATA[ This is protected ]]>
- </div>
-
-Literals
---------
-
-:: Named entities output literally
-
- >>> print render_xhtml("""\
- ... <!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">
- ... Hello World!
- ... </html>""")
- <!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">
- Hello World!
- </html>
-
-:: Although not XML-compliant, named entities are accepted even
- without a document type declaration.
-
- >>> print render_xhtml("""\
- ... <html xmlns="http://www.w3.org/1999/xhtml">
- ... Hello World!
- ... <a href="localhost" title="Singing & Dancing"
- ... >→</a>
- ... <span class="→" />
- ... </html>""")
- <html>
- Hello World!
- <a href="localhost" title="Singing & Dancing">→</a>
- <span class="→" />
- </html>
-
-:: Processing instructions output literally
-
- >>> print render_xhtml("""\
- ... <html xmlns="http://www.w3.org/1999/xhtml">
- ... <?xml-stylesheet href="classic.xsl" type="text/xml"?>
- ... Hello World!
- ... </html>""")
- <html>
- <?xml-stylesheet href="classic.xsl" type="text/xml"?>
- Hello World!
- </html>
-
-:: 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>
-
-Text templates
---------------
-
- >>> from z3c.pt.testing import render_text
-
-An example with a CSS stylesheet document:
-
- >>> css = """\
- ... #some-region {
- ... background: url(${'http://nohost/plone'}/logo.gif) no-repeat;
- ... }"""
-
- >>> print render_text(css)
- #some-region {
- background: url(http://nohost/plone/logo.gif) no-repeat;
- }
-
-A javascript document that prints out HTML:
-
- >>> js = """\
- ... print '<div class="description">Hello ${'World!'}</div>';"""
-
- >>> print render_text(js)
- print '<div class="description">Hello World!</div>';
-
-Ghosted templates
------------------
-
-To facilitate disk-caching, template instances can be pickled.
-
- >>> from z3c.pt.testing import compile_xhtml
- >>> template = compile_xhtml("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... Hello World!
- ... </div>""")
-
- >>> from pickle import dumps, loads
- >>> pickle = dumps(template)
- >>> template = loads(pickle)
-
-Check that we're getting a template object back.
-
- >>> template
- <ByteCodeTemplate parser="z3c.pt.testing.MockParser">
-
-Let's try and render the template.
-
- >>> print template.render()
- <div>
- Hello World!
- </div>
-
-
-Error handling
---------------
-
-This section demonstrates how the package handles templates that
-contain errors.
-
-:: Malformed syntax
-
-We expect the xml-parser to raise an exception.
-
- >>> body = '<div xmlns="http://www.w3.org/1999/xhtml"'
- >>> render_xhtml(body)
- Traceback (most recent call last):
- ...
- XMLSyntaxError: ...
-
-:: Missing namespace definition
-
-If a document type is provided, namespaces must be declared.
-
- >>> body = """\
- ... <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- ... "http://www.w3.org/TR/html4/loose.dtd">
- ... <div xmlns="http://www.w3.org/1999/xhtml" tal:content="'Hello World'" />
- ... """
-
- >>> print render_xhtml(body)
- Traceback (most recent call last):
- ...
- XMLSyntaxError: Namespace prefix tal for content on div is not defined...
Deleted: z3c.pt/trunk/src/z3c/pt/types.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/types.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/types.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,59 +0,0 @@
-from utils import emptydict
-
-class expression:
- symbol_mapping = emptydict()
-
-class parts(tuple, expression):
- def __repr__(self):
- return 'parts'+tuple.__repr__(self)
-
-class value(unicode, expression):
- def __init__(self, *args):
- super(value, self).__init__(*args)
- self.symbol_mapping = {}
-
- def __repr__(self):
- try:
- r = repr(self.encode())
- except UnicodeEncodeError:
- r = unicode.__repr__(self)
-
- return "value(%s)" % r
-
-class template(value):
- def __repr__(self):
- return 'template(%s)' % str.__repr__(self)
-
-class join(tuple, expression):
- def __repr__(self):
- return 'join'+tuple.__repr__(self)
-
-class declaration(tuple):
- global_scope = False
-
- def __repr__(self):
- items = map(repr, self)
- if self.global_scope:
- items.append('global_scope=%s' % repr(self.global_scope))
- return 'declaration(%s)' % ', '.join(items)
-
-class mapping(tuple):
- def __repr__(self):
- return 'mapping'+tuple.__repr__(self)
-
-class definitions(tuple):
- def __repr__(self):
- return 'definitions'+tuple.__repr__(self)
-
-class escape(parts):
- def __repr__(self):
- return 'escape'+tuple.__repr__(self)
-
-class method(object):
- def __init__(self, name, args):
- self.name = name
- self.args = args
-
- def __repr__(self):
- return "%s(%s)" % (self.name, ", ".join(arg for arg in self.args))
-
Deleted: z3c.pt/trunk/src/z3c/pt/utils.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/utils.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/utils.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,256 +0,0 @@
-from zope import interface
-
-import sys
-import config
-import logging
-import interfaces
-import htmlentitydefs
-import re, string
-
-from UserDict import UserDict
-
-# check if we're able to coerce unicode to str
-try:
- str(u'La Pe\xf1a')
- unicode_required_flag = False
-except UnicodeEncodeError:
- unicode_required_flag = True
- log = logging.getLogger('z3c.pt')
- log.info("Default system encoding is set to '%s'; "
- "the template engine will perform better if "
- "an encoding that coerces gracefully to "
- "unicode is used ('utf-8' recommended)." % sys.getdefaultencoding())
-
-def coerces_gracefully(encoding):
- if encoding != sys.getdefaultencoding() and unicode_required_flag:
- return False
- return True
-
-s_counter = 0
-
-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
-
-def attribute(ns, 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:
- return default
- def set(self, value):
- self.attrib[ns] = value
- return property(get, set)
-
-def escape(string, quote=None, encoding=None):
- if not isinstance(string, unicode) and encoding:
- string = string.decode(encoding)
- else:
- encoding = None
-
- table = htmlentitydefs.codepoint2name
- def get(char):
- key = ord(char)
- if key in table:
- return '&%s;' % table[key]
- return char
-
- string = "".join(map(get, string))
-
- if quote is not None:
- string = string.replace(quote, '\\'+quote)
-
- if encoding:
- string = string.encode(encoding)
-
- return string
-
-def identity(x):
- return x
-
-class scope(list):
- def __init__(self, *args):
- global s_counter
- self.hash = s_counter
- s_counter += 1
-
- def __hash__(self):
- return self.hash
-
-class emptydict(dict):
- def __setitem__(self, key, value):
- raise TypeError("Read-only dictionary does not support assignment.")
-
-class repeatitem(object):
- interface.implements(interfaces.ITALESIterator)
-
- def __init__(self, iterator, length):
- self.length = length
- self.iterator = iterator
-
- @property
- def index(self):
- try:
- length = len(self.iterator)
- except TypeError:
- length = self.iterator.__length_hint__()
- except:
- raise TypeError("Unable to determine length.")
-
- try:
- return self.length - length - 1
- except TypeError:
- return None
-
- @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 insert(self, key, iterable):
- try:
- length = len(iterable)
- except TypeError:
- length = None
-
- try:
- # We used to do iterable.__iter__() but, e.g. BTreeItems
- # objects are iterable (via __getitem__) but don't possess
- # an __iter__. call iter(iterable) instead to determine
- # iterability.
- iterator = iter(iterable)
- except TypeError:
- raise TypeError(
- "Can only repeat over an iterable object (%s)." % iterable)
-
- self[key] = (iterator, length)
- return iterator
-
- def __getitem__(self, key):
- value, length = dict.__getitem__(self, key)
-
- if not isinstance(value, repeatitem):
- value = repeatitem(value, length)
- self[key] = (value, length)
-
- return value
-
-class odict(UserDict):
- def __init__(self, dict = None):
- self._keys = []
- UserDict.__init__(self, dict)
-
- def __delitem__(self, key):
- UserDict.__delitem__(self, key)
- self._keys.remove(key)
-
- def __setitem__(self, key, item):
- """Case insensitive set item."""
-
- keys = tuple(key.lower() for key in self._keys)
- _key = key.lower()
- if _key in keys:
- for k in self._keys:
- if k.lower() == _key:
- self._keys.remove(k)
- key = k
- break
-
- UserDict.__setitem__(self, key, item)
- self._keys.append(key)
-
- def clear(self):
- UserDict.clear(self)
- self._keys = []
-
- def copy(self):
- dict = UserDict.copy(self)
- dict._keys = self._keys[:]
- return dict
-
- def items(self):
- return zip(self._keys, self.values())
-
- def keys(self):
- return self._keys
-
- def popitem(self):
- try:
- key = self._keys[-1]
- except IndexError:
- raise KeyError('dictionary is empty')
-
- val = self[key]
- del self[key]
-
- return (key, val)
-
- def setdefault(self, key, failobj = None):
- UserDict.setdefault(self, key, failobj)
- if key not in self._keys: self._keys.append(key)
-
- def update(self, dict):
- UserDict.update(self, dict)
- for key in dict.keys():
- if key not in self._keys: self._keys.append(key)
-
- def values(self):
- return map(self.get, self._keys)
-
-def get_attributes_from_namespace(element, namespace):
- if element.nsmap.get(element.prefix) == namespace:
- return dict([
- (name, value) for (name, value) in element.attrib.items() \
- if '{' not in name])
-
- return dict([
- (name, value) for (name, value) in element.attrib.items() \
- if name.startswith('{%s}' % namespace)])
-
-def get_namespace(element):
- if '}' in element.tag:
- return element.tag.split('}')[0][1:]
- return element.nsmap[None]
-
-def xhtml_attr(name):
- return "{%s}%s" % (config.XHTML_NS, name)
-
-def tal_attr(name):
- return "{%s}%s" % (config.TAL_NS, name)
-
-def meta_attr(name):
- return "{%s}%s" % (config.META_NS, name)
-
-def metal_attr(name):
- return "{%s}%s" % (config.METAL_NS, name)
-
-def i18n_attr(name):
- return "{%s}%s" % (config.I18N_NS, name)
-
-def py_attr(name):
- return "{%s}%s" % (config.PY_NS, name)
Deleted: z3c.pt/trunk/src/z3c/pt/zpt.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/zpt.py 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/zpt.py 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,231 +0,0 @@
-from zope import component
-
-import translation
-import interfaces
-import itertools
-import utils
-import config
-import etree
-
-class ZopePageTemplateElement(
- translation.Element, translation.VariableInterpolation,
- translation.NativeAttributePrefixSupport):
- """Zope Page Template element.
-
- Implements the ZPT subset of the attribute template language.
- """
-
- class node(translation.Node):
- @property
- def omit(self):
- if self.element.tal_omit is not None:
- return self.element.tal_omit or True
- if self.element.meta_omit is not None:
- return self.element.meta_omit or True
- if self.element.tal_replace or self.element.meta_replace:
- return True
- if self.element.metal_use or self.element.metal_fillslot:
- return True
-
- @property
- def define(self):
- return self.element.tal_define
-
- @property
- def condition(self):
- return self.element.tal_condition
-
- @property
- def repeat(self):
- return self.element.tal_repeat
-
- @property
- def content(self):
- return self.element.tal_content or self.element.tal_replace or \
- self.element.meta_replace
-
- @property
- def skip(self):
- if self.define_slot:
- variable = self.symbols.slot + self.define_slot
- if variable in itertools.chain(*self.stream.scope):
- return True
-
- return self.content or \
- self.use_macro or self.translate is not None
-
- @property
- def dynamic_attributes(self):
- return (self.element.tal_attributes or ()) + \
- (self.element.meta_attributes or ())
-
- @property
- def translated_attributes(self):
- return self.element.i18n_attributes
-
- @property
- def static_attributes(self):
- return utils.get_attributes_from_namespace(
- self.element, config.XHTML_NS)
-
- @property
- def translate(self):
- return self.element.i18n_translate
-
- @property
- def translation_name(self):
- return self.element.i18n_name
-
- @property
- def translation_domain(self):
- return self.element.i18n_domain
-
- @property
- def use_macro(self):
- return self.element.metal_use
-
- @property
- def define_macro(self):
- return self.element.metal_define
-
- @property
- def define_slot(self):
- return self.element.metal_defineslot
-
- @property
- def fill_slot(self):
- return self.element.metal_fillslot
-
- @property
- def cdata(self):
- return self.element.meta_cdata
-
- @property
- def default_expression(self):
- return self.element.tal_default_expression
-
- node = property(node)
-
- @property
- def translator(self):
- while self.node.default_expression is None:
- self = self.getparent()
- if self is None:
- raise ValueError("Default expression not set.")
-
- return component.getUtility(
- interfaces.IExpressionTranslation, name=self.node.default_expression)
-
- def update(self):
- translation.NativeAttributePrefixSupport.update(self)
- translation.VariableInterpolation.update(self)
-
-class XHTMLElement(ZopePageTemplateElement):
- """XHTML namespace element."""
-
- tal_define = utils.attribute(
- utils.tal_attr('define'), lambda p: p.definitions)
- tal_condition = utils.attribute(
- utils.tal_attr('condition'), lambda p: p.expression)
- tal_repeat = utils.attribute(
- utils.tal_attr('repeat'), lambda p: p.definition)
- tal_attributes = utils.attribute(
- utils.tal_attr('attributes'), lambda p: p.definitions)
- tal_content = utils.attribute(
- utils.tal_attr('content'), lambda p: p.output)
- tal_replace = utils.attribute(
- utils.tal_attr('replace'), lambda p: p.output)
- tal_omit = utils.attribute(
- utils.tal_attr('omit-tag'), lambda p: p.expression)
- tal_default_expression = utils.attribute(
- utils.tal_attr('default-expression'), encoding='ascii')
- metal_define = utils.attribute(
- utils.metal_attr('define-macro'), lambda p: p.method)
- metal_use = utils.attribute(
- utils.metal_attr('use-macro'), lambda p: p.expression)
- metal_fillslot = utils.attribute(
- utils.metal_attr('fill-slot'))
- metal_defineslot = utils.attribute(
- utils.metal_attr('define-slot'))
- i18n_translate = utils.attribute(
- utils.i18n_attr('translate'))
- i18n_attributes = utils.attribute(
- utils.i18n_attr('attributes'), lambda p: p.mapping)
- i18n_domain = utils.attribute(
- utils.i18n_attr('domain'))
- i18n_name = utils.attribute(
- utils.i18n_attr('name'))
-
-class MetaElement(XHTMLElement, translation.MetaElement):
- pass
-
-class TALElement(ZopePageTemplateElement):
- """TAL namespace element."""
-
- tal_define = utils.attribute("define", lambda p: p.definitions)
- tal_condition = utils.attribute("condition", lambda p: p.expression)
- tal_replace = utils.attribute("replace", lambda p: p.output)
- tal_repeat = utils.attribute("repeat", lambda p: p.definition)
- tal_attributes = utils.attribute("attributes", lambda p: p.expression)
- tal_content = utils.attribute("content", lambda p: p.output)
- tal_omit = utils.attribute("omit-tag", lambda p: p.expression, u"")
- tal_default_expression = utils.attribute(
- 'default-expression')
- tal_cdata = utils.attribute("cdata")
-
- metal_define = None
- metal_use = None
- metal_fillslot = None
- metal_defineslot = None
- i18n_domain = None
- i18n_translate = None
- i18n_attributes = None
-
-class METALElement(ZopePageTemplateElement):
- """METAL namespace element."""
-
- tal_define = None
- tal_condition = None
- tal_replace = None
- tal_content = None
- tal_repeat = None
- tal_attributes = None
- tal_omit = True
- tal_default_expression = None
- tal_cdata = None
- metal_define = utils.attribute('define-macro', lambda p: p.method)
- metal_use = utils.attribute('use-macro', lambda p: p.expression)
- metal_fillslot = utils.attribute('fill-slot')
- metal_defineslot = utils.attribute('define-slot')
- i18n_domain = None
- i18n_translate = None
- i18n_attributes = None
-
-class ZopePageTemplateParser(etree.Parser):
- """ The parser implementation for ZPT """
- element_mapping = {
- config.XHTML_NS: {None: XHTMLElement},
- config.META_NS: {None: MetaElement},
- config.TAL_NS: {None: TALElement},
- config.METAL_NS: {None: METALElement}}
-
- default_expression = 'python'
-
- def __init__(self, default_expression=None):
- if default_expression is not None:
- self.default_expression = default_expression
-
- def parse(self, body):
- root, doctype = super(ZopePageTemplateParser, self).parse(body)
- # if a default expression is not set explicitly in the
- # template, use the TAL-attribute ``default-expression``
- # to set it
- if utils.get_namespace(root) == config.TAL_NS:
- tag = 'default-expression'
- else:
- tag = utils.tal_attr('default-expression')
-
- if not root.attrib.get(tag):
- root.attrib[tag] = self.default_expression
-
- return root, doctype
Deleted: z3c.pt/trunk/src/z3c/pt/zpt.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/zpt.txt 2008-10-02 19:44:09 UTC (rev 91671)
+++ z3c.pt/trunk/src/z3c/pt/zpt.txt 2008-10-02 19:46:03 UTC (rev 91672)
@@ -1,409 +0,0 @@
-Zope Page Templates (ZPT)
-=========================
-
- >>> from z3c.pt.testing import render_zpt
-
-TAL
----
-
-:: Namespace elements
-
- >>> print render_zpt("""\
- ... <tal:block xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... Hello, world!
- ... </tal:block>""")
- <BLANKLINE>
- Hello, world!
- <BLANKLINE>
-
-tal:define, tal:attributes, tal:contents
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <span id="test"
- ... class="dummy"
- ... onclick=""
- ... tal:define="a 'abc'"
- ... tal:attributes="class 'def' + a; style 'hij'; onClick 'alert();'"
- ... tal:content="a + 'ghi'" />
- ... <span tal:replace="'Hello World!'">Hello <b>Universe</b>!</span>
- ... <span tal:replace="'Hello World!'"><b>Hello Universe!</b></span>
- ... <span tal:content="None" />
- ... </div>""")
- <div>
- <span class="defabc" style="hij" onclick="alert();" id="test">abcghi</span>
- Hello World!
- Hello World!
- <span></span>
- </div>
-
-tal:attributes 'checked' and 'selected' toggles
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <option tal:attributes="selected True"/>
- ... <option tal:attributes="selected None"/>
- ... <input tal:attributes="checked True"/>
- ... <input tal:attributes="checked False"/>
- ... </div>""")
- <div>
- <option selected="True" />
- <option />
- <input checked="True" />
- <input />
- </div>
-
-tal:repeat
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <ul>
- ... <li tal:repeat="i range(5)"><span tal:replace="'Item ' + str(i) + ')'" /></li>
- ... </ul>
- ... </div>""")
- <div>
- <ul>
- <li>Item 0)</li>
- <li>Item 1)</li>
- <li>Item 2)</li>
- <li>Item 3)</li>
- <li>Item 4)</li>
- </ul>
- </div>
-
-tal:repeat (repeat-variable)
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <ul>
- ... <li tal:repeat="i range(3)"><span tal:replace="str(i) + ' ' + str(repeat['i'].even())" /></li>
- ... </ul>
- ... </div>""")
- <div>
- <ul>
- <li>0 True</li>
- <li>1 False</li>
- <li>2 True</li>
- </ul>
- </div>
-
-tal:condition
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <div tal:condition="True">
- ... Show me!
- ... </div>
- ... <div tal:condition="False">
- ... Do not show me!
- ... </div>
- ... </div>""")
- <div>
- <div>
- Show me!
- </div>
- </div>
-
-:: HTML comments
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <!-- a comment -->
- ... <!-- a multi-
- ... line comment -->
- ... <!-- a comment with an ${'expression'} -->
- ... </div>""")
- <div>
- <!-- a comment -->
- <!-- a multi-
- line comment -->
- <!-- a comment with an expression -->
- </div>
-
-:: TAL elements with namespace prefix
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <tal:example replace="'Hello World!'" />
- ... <tal:example tal:replace="'Hello World!'" />
- ... <tal:div content="'Hello World!'" />
- ... <tal:multiple repeat="i range(3)" replace="i" />
- ... <tal:div condition="True">True</tal:div>
- ... </div>""")
- <div>
- Hello World!
- Hello World!
- Hello World!
- 0
- 1
- 2
- True
- </div>
-
-tal:omit-tag
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <p tal:omit-tag="">No paragraph here.</p>
- ... <p tal:omit-tag="True">No paragraph here either.</p>
- ... <p tal:omit-tag="False">A paragraph here.</p>
- ... </div>""")
- <div>
- No paragraph here.
- No paragraph here either.
- <p>A paragraph here.</p>
- </div>
-
-:: Unicode with dynamic attributes and content
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <img tal:attributes="title '%sHello%s' % (chr(60), chr(62))" />
- ... <span tal:replace="structure '%sbr /%s' % (chr(60), chr(62))" />
- ... <span tal:replace="'%sbr /%s' % (chr(60), chr(62))" />
- ... <span tal:content="unicode('La Pe\xc3\xb1a', 'utf-8')" />
- ... </div>""")
- <div>
- <img title="<Hello>" />
- <br />
- <br />
- <span>La Peña</span>
- </div>
-
-:: Using the "path:" expression
-
- >>> class Test(object):
- ... greeting = u'Hello'
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <span tal:replace="path: test1/greeting" />
- ... <span tal:replace="path: test2/greeting" />
- ... </div>""", request=object(),
- ... test1={'greeting': u'Hello'}, test2=Test())
- <div>
- Hello
- Hello
- </div>
-
-:: Using the "string:" expression
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <span tal:replace="string:${greeting}, world!" />
- ... <img tal:attributes="alt string:Leonardo da Vinci;; Musee du Louvre, 1503;
- ... title string:Mona Lisa" />
- ... </div>""", request=object(), greeting=u'Hello')
- <div>
- Hello, world!
- <img alt="Leonardo da Vinci; Musee du Louvre, 1503" title="Mona Lisa" />
- </div>
-
-:: Using the "provider:" expression
-
- >>> class Context(object): pass
- >>> class Request(object): pass
- >>> class View(object): pass
-
-This directive renders a content provider; let's define and register a
-content provider which allows us to verify the functionality of the
-expression.
-
- >>> from zope.contentprovider.interfaces import IContentProvider
- >>> from zope import component
- >>> from zope import interface
-
- >>> class DummyContentProvider(object):
- ... component.adapts(Context, Request, View)
- ... interface.implements(IContentProvider)
- ...
- ... def __init__(self, context, request, view):
- ... self.context = context
- ... self.request = request
- ... self.view = view
- ...
- ... def update(self):
- ... self.updated = True
- ...
- ... def render(self):
- ... return type(self.context), type(self.request), \
- ... type(self.view), self.updated
-
- >>> component.provideAdapter(
- ... DummyContentProvider, name="test")
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <span tal:replace="structure provider:test" />
- ... </div>""", context=Context(), request=Request(), view=View())
- <div>
- (<class 'Context'>, <class 'Request'>, <class 'View'>, True)
- </div>
-
-:: Setting the default expression
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <div tal:default-expression="path">
- ... <span tal:replace="test/greeting" />
- ... </div>
- ... </div>""", request=object(), test={'greeting': u'Hello'})
- <div>
- <div>
- Hello
- </div>
- </div>
-
-:: Using different expressions with try-except operator (|)
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <tal:path-expression-testing
- ... define="request object();
- ... mydict {'a': 1, 'c': {'a': 2}}">
- ... <div tal:default-expression="path">
- ... <span tal:replace="mydict/a" />
- ... <span tal:replace="mydict/b|mydict/a" />
- ... <span tal:replace="mydict/c/a" />
- ... <span tal:replace="python: 5+5" />
- ... </div>
- ... <span tal:replace="path: mydict/a" />
- ... <span tal:replace="python: 1+1" />
- ... <span tal:replace="path: mydict/b|True" />
- ... <span tal:replace="int('a')|path: mydict/a" />
- ... </tal:path-expression-testing>
- ... </div>""")
- <div>
- <BLANKLINE>
- <div>
- 1
- 1
- 2
- 10
- </div>
- 1
- 2
- True
- 1
- <BLANKLINE>
- </div>
-
-:: Using TAL pragmas "nocall" and "structure"
-
- >>> print render_zpt("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal">
- ... <span tal:default-expression="path"
- ... tal:replace="structure nocall: dir" />
- ... <span tal:replace="structure dir" />
- ... </div>""", request=object())
- <div>
- <built-in function dir>
- <built-in function dir>
- </div>
-
-METAL
------
-
-metal:define-macro, metal:use-macro
-
- >>> body = """\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal"
- ... xmlns:metal="http://xml.zope.org/namespaces/metal">
- ... <div class="greeting" metal:define-macro="greeting">
- ... Hello, ${name|string:earth}!
- ... </div>
- ... <div tal:define="name 'world'">
- ... <div metal:use-macro="template.macros['greeting']" />
- ... </div>
- ... </div>"""
-
- >>> from z3c.pt.testing import MockTemplate
- >>> from z3c.pt.zpt import ZopePageTemplateParser
-
- >>> template = MockTemplate(body, ZopePageTemplateParser())
- >>> print render_zpt(body, template=template)
- <div>
- <div class="greeting">
- Hello, earth!
- </div>
- <div>
- <div class="greeting">
- Hello, world!
- </div>
- <BLANKLINE>
- </div>
- </div>
-
-metal:define-slot, metal:fill-slot
-
- >>> body = """\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:tal="http://xml.zope.org/namespaces/tal"
- ... xmlns:metal="http://xml.zope.org/namespaces/metal">
- ... <div metal:define-macro="greeting">
- ... Hey, <span class="name" metal:define-slot="name">
- ... a <em>stranger!</em></span>
- ... </div>
- ... <div metal:use-macro="template.macros['greeting']">
- ... This will be omitted
- ... <span metal:fill-slot="name">earth!</span>
- ... </div>
- ... <div metal:use-macro="template.macros['greeting']">
- ... <div>
- ... <metal:earth fill-slot="name">earth!</metal:earth>
- ... </div>
- ... </div>
- ... <div metal:use-macro="template.macros['greeting']">
- ... <!-- display fallback greeting -->
- ... </div>
- ... <div metal:use-macro="template.macros['greeting']">
- ... <span metal:fill-slot="dummy">dummy!</span>
- ... </div>
- ... </div>"""
-
- >>> from z3c.pt.testing import MockTemplate
-
- >>> template = MockTemplate(body, ZopePageTemplateParser())
- >>> print render_zpt(body, template=template)
- <div>
- <div>
- Hey, <span class="name">
- a <em>stranger!</em></span>
- </div>
- <div>
- Hey, <span class="name">earth!</span>
- </div>
- <BLANKLINE>
- <div>
- Hey, <span class="name">earth!</span>
- </div>
- <BLANKLINE>
- <div>
- Hey, <span class="name">
- a <em>stranger!</em></span>
- </div>
- <BLANKLINE>
- <div>
- Hey, <span class="name">
- a <em>stranger!</em></span>
- </div>
- <BLANKLINE>
- </div>
-
-
More information about the Checkins
mailing list