[Checkins] SVN: z3c.pt/trunk/ Started development of 2.x series, following stable build of Chameleon 2.x series. This commit marks a stable development version.
Malthe Borch
mborch at gmail.com
Mon Feb 21 04:01:03 EST 2011
Log message for revision 120484:
Started development of 2.x series, following stable build of Chameleon 2.x series. This commit marks a stable development version.
Changed:
U z3c.pt/trunk/CHANGES.txt
D z3c.pt/trunk/benchmark/
U z3c.pt/trunk/bootstrap.py
U z3c.pt/trunk/buildout.cfg
U z3c.pt/trunk/setup.py
U z3c.pt/trunk/src/z3c/pt/README.txt
U z3c.pt/trunk/src/z3c/pt/configure.zcml
U z3c.pt/trunk/src/z3c/pt/expressions.py
D z3c.pt/trunk/src/z3c/pt/language.py
U z3c.pt/trunk/src/z3c/pt/loader.py
U z3c.pt/trunk/src/z3c/pt/pagetemplate.py
U z3c.pt/trunk/src/z3c/pt/tests/test_doctests.py
U z3c.pt/trunk/src/z3c/pt/tests/test_loader.py
D z3c.pt/trunk/src/z3c/pt/texttemplate.py
-=-
Modified: z3c.pt/trunk/CHANGES.txt
===================================================================
--- z3c.pt/trunk/CHANGES.txt 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/CHANGES.txt 2011-02-21 09:01:02 UTC (rev 120484)
@@ -3,6 +3,34 @@
In next release...
+- Update to Chameleon 2.0.
+
+ This release includes many changes and is a complete rewrite of the
+ 1.x series.
+
+ Platform:
+
+ * Python 2.7+ now required.
+
+ Notable changes:
+
+ * Expression interpolation is always enabled.
+
+ * Whitespace output is different, now closely aligned to the
+ template input.
+
+ * New language constructs:
+
+ 1) tal:on-error
+ 2) tal:switch
+ 3) tal:case
+
+ Incompatibilities:
+
+ * The expression translation interface has been replaced with an
+ expression engine. This means that all expressions must be
+ rewritten.
+
- The exists expression evaluator should ignore KeyError exceptions
as well.
Modified: z3c.pt/trunk/bootstrap.py
===================================================================
--- z3c.pt/trunk/bootstrap.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/bootstrap.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -16,37 +16,104 @@
Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
-
-$Id: bootstrap.py 71627 2006-12-20 16:46:11Z jim $
"""
import os, shutil, sys, tempfile, urllib2
+from optparse import OptionParser
tmpeggs = tempfile.mkdtemp()
-ez = {}
-exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
- ).read() in ez
-ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+is_jython = sys.platform.startswith('java')
-import pkg_resources
+# parsing arguments
+parser = OptionParser()
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="distribute", default=False,
+ help="Use Disribute rather than Setuptools.")
-cmd = 'from setuptools.command.easy_install import main; main()'
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.version is not None:
+ VERSION = '==%s' % options.version
+else:
+ VERSION = ''
+
+USE_DISTRIBUTE = options.distribute
+args = args + ['bootstrap']
+
+to_reload = False
+try:
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ to_reload = True
+ raise ImportError
+except ImportError:
+ ez = {}
+ if USE_DISTRIBUTE:
+ exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
+ else:
+ exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ if to_reload:
+ reload(pkg_resources)
+ else:
+ import pkg_resources
+
if sys.platform == 'win32':
- cmd = '"%s"' % cmd # work around spawn lamosity on windows
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ def quote (c):
+ return c
-ws = pkg_resources.working_set
-assert os.spawnle(
- os.P_WAIT, sys.executable, sys.executable,
- '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
- dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse('setuptools')).location
- ),
- ) == 0
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws = pkg_resources.working_set
+if USE_DISTRIBUTE:
+ requirement = 'distribute'
+else:
+ requirement = 'setuptools'
+
+if is_jython:
+ import subprocess
+
+ assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
+ quote(tmpeggs), 'zc.buildout' + VERSION],
+ env=dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse(requirement)).location
+ ),
+ ).wait() == 0
+
+else:
+ assert os.spawnle(
+ os.P_WAIT, sys.executable, quote (sys.executable),
+ '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse(requirement)).location
+ ),
+ ) == 0
+
ws.add_entry(tmpeggs)
-ws.require('zc.buildout')
+ws.require('zc.buildout' + VERSION)
import zc.buildout.buildout
-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)
Modified: z3c.pt/trunk/buildout.cfg
===================================================================
--- z3c.pt/trunk/buildout.cfg 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/buildout.cfg 2011-02-21 09:01:02 UTC (rev 120484)
@@ -1,7 +1,7 @@
[buildout]
develop = .
- benchmark
-parts = test benchmark py
+eggs = z3c.pt chameleon
+parts = test py
versions = versions
[versions]
@@ -27,33 +27,14 @@
[test]
recipe = zc.recipe.testrunner
-environment = test-environment
eggs =
z3c.pt
-[test-environment]
-CHAMELEON_DEBUG = False
-CHAMELEON_CACHE = False
-
-[benchmark]
-recipe = zc.recipe.testrunner
-environment = benchmark-environment
-eggs =
- z3c.pt
- benchmark
-
-[benchmark-environment]
-CHAMELEON_DEBUG = False
-CHAMELEON_CACHE = False
-zope_i18n_allowed_languages = en, da, de
-
[py]
recipe = zc.recipe.egg
eggs =
z3c.pt
- benchmark
Sphinx
zope.testing
interpreter = py
-environment = benchmark-environment
scripts = sphinx-build
Modified: z3c.pt/trunk/setup.py
===================================================================
--- z3c.pt/trunk/setup.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/setup.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
import sys
-version = '1.2.2dev'
+version = '2.0-dev'
install_requires = [
'setuptools',
@@ -10,12 +10,9 @@
'zope.i18n >= 3.5',
'zope.traversing',
'zope.contentprovider',
- 'Chameleon >= 1.2.3',
+ 'Chameleon >= 2.0-dev',
]
-if sys.version_info[:3] < (2,5,0):
- install_requires.append('elementtree')
-
setup(name='z3c.pt',
version=version,
description="Fast ZPT template engine.",
Modified: z3c.pt/trunk/src/z3c/pt/README.txt
===================================================================
--- z3c.pt/trunk/src/z3c/pt/README.txt 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/README.txt 2011-02-21 09:01:02 UTC (rev 120484)
@@ -22,7 +22,6 @@
Hello World!
</div>
-
The ``PageTemplateFile`` class is initialized with an absolute
path to a template file on disk.
@@ -181,61 +180,6 @@
</div>
-Dollar-Interpolation
---------------------
-
-As ``z3c.pt` **should** be as compatible as possible to it's original,
-we don't allow $-interpolation like in ``chameleon.zpt``::
-
- >>> template = PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml">
- ... ${this does not break}
- ... </div>""")
-
- >>> print template()
- <div xmlns="http://www.w3.org/1999/xhtml">
- ${this does not break}
- </div>
-
-But we can **enable** this in a template::
-
- >>> template = PageTemplate("""\
- ... <div xmlns="http://www.w3.org/1999/xhtml"
- ... xmlns:meta="http://xml.zope.org/namespaces/meta">
- ... <div meta:interpolation="true">
- ... ${options/foo}
- ... </div>
- ... </div>""")
-
- >>> print template(foo=u'bar')
- <div xmlns="http://www.w3.org/1999/xhtml">
- <div>
- bar
- </div>
- </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('tests/view.css')
- >>> print template.bind(view)(color=u'#ccc')
- #region {
- background: #ccc;
- }
-
- >>> template = ViewTextTemplate('print "<html>${options/color}</html>";')
- >>> print template.bind(view)(color=u'#ccc')
- print "<html>#ccc</html>";
-
Non-keyword arguments
---------------------
@@ -316,8 +260,7 @@
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
- ... <span tal:content="options/not-existing | default"
- ... >default content</span>
+ ... <span tal:content="options/not-existing | default">default content</span>
... </div>""")
>>> print template()
@@ -332,10 +275,8 @@
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
- ... <span tal:content="python: exists('options/nope') and 'Yes' or 'No'"
- ... >do I exist?</span>
- ... <span tal:content="python: exists('nope') and 'Yes' or 'No'"
- ... >do I exist?</span>
+ ... <span tal:content="python: exists('options/nope') and 'Yes' or 'No'">do I exist?</span>
+ ... <span tal:content="python: exists('nope') and 'Yes' or 'No'">do I exist?</span>
... </div>""")
>>> print template()
@@ -349,11 +290,9 @@
>>> template = PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
... <span tal:define="yup exists:options/nope"
- ... tal:content="python: yup and 'Yes' or 'No'"
- ... >do I exist?</span>
+ ... tal:content="python: yup and 'Yes' or 'No'">do I exist?</span>
... <span tal:define="yup exists:nope"
- ... tal:content="python: yup and 'Yes' or 'No'"
- ... >do I exist?</span>
+ ... tal:content="python: yup and 'Yes' or 'No'">do I exist?</span>
... </div>""")
>>> print template()
@@ -366,8 +305,7 @@
>>> print PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml">
- ... <span tal:condition="not:exists:options/nope"
- ... >I don't exist?</span>
+ ... <span tal:condition="not:exists:options/nope">I don't exist?</span>
... </div>""")()
<div xmlns="http://www.w3.org/1999/xhtml">
<span>I don't exist?</span>
@@ -382,8 +320,7 @@
>>> print PageTemplate("""\
... <div xmlns="http://www.w3.org/1999/xhtml"
... tal:define="links python:{'copy':'XXX', 'delete':'YYY'}">
- ... <span tal:content="links/copy"
- ... >ZZZ</span>
+ ... <span tal:content="links/copy">ZZZ</span>
... </div>""")()
<div xmlns="http://www.w3.org/1999/xhtml">
<span>XXX</span>
Modified: z3c.pt/trunk/src/z3c/pt/configure.zcml
===================================================================
--- z3c.pt/trunk/src/z3c/pt/configure.zcml 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/configure.zcml 2011-02-21 09:01:02 UTC (rev 120484)
@@ -4,31 +4,32 @@
<include package="zope.component" file="meta.zcml" />
- <include package="chameleon.core" />
- <include package="chameleon.zpt" />
-
- <utility
- name="path"
- component=".expressions.path_translator" />
+ <!--
- <adapter
- name="not"
- factory=".expressions.NotTranslator" />
+ <utility
+ name="path"
+ component=".expressions.path_translator" />
- <utility
- name="provider"
- component=".expressions.provider_translator" />
+ <adapter
+ name="not"
+ factory=".expressions.NotTranslator" />
- <utility
- name="exists"
- component=".expressions.exists_translator" />
+ <utility
+ name="provider"
+ component=".expressions.provider_translator" />
+ <utility
+ name="exists"
+ component=".expressions.exists_translator" />
+
+ -->
+
<configure zcml:condition="installed zope.security">
<include package="zope.security" file="meta.zcml" />
- <class class="chameleon.core.utils.repeatitem">
- <allow interface="chameleon.core.interfaces.ITALESIterator" />
+ <class class="chameleon.tal.RepeatItem">
+ <allow interface="chameleon.interfaces.ITALESIterator" />
</class>
<class class=".pagetemplate.BoundPageTemplate">
@@ -38,4 +39,4 @@
</configure>
</configure>
-
+
Modified: z3c.pt/trunk/src/z3c/pt/expressions.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/expressions.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/expressions.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -1,3 +1,4 @@
+import ast
import re
import namespaces
import zope.event
@@ -12,18 +13,24 @@
except ImportError:
BeforeUpdateEvent = None
-from chameleon.core import types
-from chameleon.zpt import expressions
-from chameleon.zpt.interfaces import IExpressionTranslator
-
from types import MethodType
+from chameleon.tales import PathExpr as BasePathExpr
+from chameleon.tales import ExistsExpr as BaseExistsExpr
+from chameleon.codegen import template
+from chameleon.astutil import load
+from chameleon.astutil import Symbol
+from chameleon.astutil import Static
+from chameleon.exc import ExpressionError
+
_marker = object()
_valid_name = re.compile(r"[a-zA-Z][a-zA-Z0-9_]*$").match
+
def identity(x):
return x
+
class ContentProviderTraverser(object):
def __call__(self, context, request, view, name):
cp = zope.component.queryMultiAdapter(
@@ -38,6 +45,7 @@
cp.update()
return cp.render()
+
class ZopeTraverser(object):
def __init__(self, proxify=identity):
self.proxify = proxify
@@ -83,90 +91,44 @@
return base
-class ZopeExistsTraverser(ZopeTraverser):
- exceptions = AttributeError, LookupError, TypeError, KeyError
- def __call__(self, base, request, call, *args, **kwargs):
- try:
- return ZopeTraverser.__call__(
- self, base, request, False, *args, **kwargs) is not None
- except self.exceptions:
- return False
- return True
+class ExistsExpr(BaseExistsExpr):
+ exceptions = AttributeError, LookupError, TypeError, KeyError, NameError
-class PathTranslator(expressions.ExpressionTranslator):
+
+class PathExpr(BasePathExpr):
path_regex = re.compile(
- r'^((nocall|not):\s*)*([A-Za-z_][A-Za-z0-9_:]*)'+
- r'(/[?A-Za-z_@\-+][?A-Za-z0-9_@\-\.+/:]*)*$')
+ r'^(?:(nocall|not):\s*)*((?:[A-Za-z_][A-Za-z0-9_:]*)' +
+ r'(?:/[?A-Za-z_@\-+][?A-Za-z0-9_@\-\.+/:]*)*)$')
interpolation_regex = re.compile(
r'\?[A-Za-z][A-Za-z0-9_]+')
- path_traverse = ZopeTraverser()
- scope = 'request'
+ traverser = Static(
+ template("cls()", cls=Symbol(ZopeTraverser), mode="eval")
+ )
- symbol = '_path'
-
- def translate(self, string, escape=None):
+ def translate(self, string, target):
"""
- >>> translate = PathTranslator().translate
-
- >>> translate("") is None
+ >>> from chameleon.tales import test
+ >>> test(PathExpr('')) is None
True
-
- >>> translate("nocall: a")
- value('a')
-
- >>> translate("nothing")
- value('None')
-
- >>> translate("a/b")
- value("_path(a, request, True, 'b')")
-
- Verify allowed character set.
-
- >>> translate("image_path/++res++/@@hello.html")
- value("_path(image_path, request, True, '++res++', '@@hello.html')")
-
- >>> translate("context/@@view")
- value("_path(context, request, True, '@@view')")
-
- >>> translate("nocall: context/@@view")
- value("_path(context, request, False, '@@view')")
-
- >>> translate("context/?view")
- value("_path(context, request, True, '%s' % (view,))")
-
- >>> translate("context/@@?view")
- value("_path(context, request, True, '@@%s' % (view,))")
"""
+ string = string.strip()
+
if not string:
- return None
+ return template("target = None", target=target)
- if not self.path_regex.match(string.strip()):
- raise SyntaxError("Not a valid path-expression: %s." % string)
+ m = self.path_regex.match(string)
+ if m is None:
+ raise ExpressionError("Not a valid path-expression.", string)
- nocall = False
+ nocall, path = m.groups()
- while string:
- m = self.re_pragma.match(string)
- if m is None:
- break
+ # note that unicode paths are not allowed
+ parts = str(path).split('/')
- string = string[m.end():]
- pragma = m.group('pragma').lower()
-
- if pragma == 'nocall':
- nocall = True
- else:
- raise ValueError("Invalid pragma: %s" % pragma)
-
- parts = string.strip().split('/')
-
- # map 'nothing' to 'None'
- parts = map(lambda part: part == 'nothing' and 'None' or part, parts)
-
components = []
for part in parts[1:]:
interpolation_args = []
@@ -174,7 +136,7 @@
def replace(match):
start, end = match.span()
interpolation_args.append(
- part[start+1:end])
+ part[start + 1:end])
return "%s"
while True:
@@ -183,10 +145,15 @@
break
if len(interpolation_args):
- component = "%s %% (%s,)" % (
- repr(part), ", ".join(interpolation_args))
+ component = template(
+ "format % args", format=ast.Str(part),
+ args=ast.Tuple(
+ list(map(load, interpolation_args)),
+ ast.Load()
+ ),
+ mode="eval")
else:
- component = repr(str(part))
+ component = ast.Str(part)
components.append(component)
@@ -194,98 +161,51 @@
if not components:
if len(parts) == 1 and (nocall or base == 'None'):
- value = types.value('%s' % base)
- return value
+ return template("target = base", base=base, target=target)
else:
components = ()
- value = types.value(
- '%s(%s, %s, %s, %s)' % \
- (self.symbol, base, self.scope, not nocall, ', '.join(components)))
+ call = template(
+ "traverse(base, request, call)",
+ traverse=self.traverser,
+ base=load(base),
+ call=not nocall,
+ mode="eval",
+ )
- value.symbol_mapping[self.symbol] = self.path_traverse
+ if components:
+ call.args.extend(components)
- return value
+ return template("target = value", target=target, value=call)
-class NotTranslator(expressions.ExpressionTranslator):
- zope.component.adapts(IExpressionTranslator)
- recursive = True
+class NocallExpr(PathExpr):
+ """A path-expression which does not call the resolved object."""
- def __init__(self, translator):
- self.translator = translator
+ def translate(self, expression, engine):
+ return super(NocallExpr, self).translate(
+ "nocall:%s" % expression, engine)
- def tales(self, string, escape=None):
- """
- >>> tales = NotTranslator(path_translator).tales
- >>> tales("abc/def/ghi")
- value("not(_path(abc, request, True, 'def', 'ghi'))")
-
- >>> tales("abc | def")
- parts(value('not(_path(abc, request, True, ))'),
- value('not(_path(def, request, True, ))'))
-
- >>> tales("abc | not: def")
- parts(value('not(_path(abc, request, True, ))'),
- value('not(not(_path(def, request, True, )))'))
-
- >>> tales("abc | not: def | ghi")
- parts(value('not(_path(abc, request, True, ))'),
- value('not(not(_path(def, request, True, )))'),
- value('not(not(_path(ghi, request, True, )))'))
- """
-
- value = self.translator.tales(string, escape=escape)
- if isinstance(value, types.value):
- value = (value,)
-
- parts = []
- for part in value:
- factory = type(part)
- value = factory("not(%s)" % part)
- value.symbol_mapping.update(part.symbol_mapping)
- parts.append(value)
-
- if len(parts) == 1:
- return parts[0]
-
- return types.parts(parts)
-
-class ProviderTranslator(expressions.ExpressionTranslator):
+class ProviderExpr(object):
provider_regex = re.compile(r'^[A-Za-z][A-Za-z0-9_\.-]*$')
- symbol = '_get_content_provider'
- content_provider_traverser = ContentProviderTraverser()
+ traverser = Static(
+ template("cls()", cls=Symbol(ContentProviderTraverser), mode="eval")
+ )
- def translate(self, string, escape=None):
+ def __init__(self, expression):
+ self.expression = expression
+
+ def __call__(self, target, engine):
+ string = self.expression.strip()
if self.provider_regex.match(string) is None:
raise SyntaxError(
"%s is not a valid content provider name." % string)
- value = types.value("%s(context, request, view, '%s')" % \
- (self.symbol, string))
- value.symbol_mapping[self.symbol] = self.content_provider_traverser
- return value
-
-class ExistsTranslator(PathTranslator):
- """Implements string translation expression."""
-
- symbol = '_path_exists'
-
- path_traverse = ZopeExistsTraverser()
-
- def translate(self, *args, **kwargs):
- value = super(ExistsTranslator, self).translate(*args, **kwargs)
- if value is None:
- return
-
- assert isinstance(value, types.value)
- parts = types.parts(
- (value, types.value('False')))
- parts.exceptions = NameError,
- return parts
-
-exists_translator = ExistsTranslator()
-path_translator = PathTranslator()
-provider_translator = ProviderTranslator()
+ return template(
+ "target = traverse(context, request, view, name)",
+ target=target,
+ traverse=self.traverser,
+ name=ast.Str(string),
+ )
Deleted: z3c.pt/trunk/src/z3c/pt/language.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/language.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/language.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -1,37 +0,0 @@
-from chameleon.core import translation
-from chameleon.core import config
-from chameleon.core import utils
-
-import chameleon.zpt.language
-
-class ZopePageTemplateElement(chameleon.zpt.language.ZopePageTemplateElement):
- meta_interpolation = utils.attribute(
- utils.meta_attr('interpolation'), default="false", recursive=True)
-
-class XHTMLElement(chameleon.zpt.language.XHTMLElement):
- meta_interpolation = utils.attribute(
- utils.meta_attr('interpolation'), default="false", recursive=True)
-
-class TALElement(chameleon.zpt.language.TALElement):
- meta_interpolation = utils.attribute(
- utils.meta_attr('interpolation'), default="false", recursive=True)
-
-class METALElement(chameleon.zpt.language.METALElement):
- meta_interpolation = utils.attribute(
- utils.meta_attr('interpolation'), default="false", recursive=True)
-
-class MetaElement(chameleon.zpt.language.MetaElement):
- meta_interpolation = utils.attribute(
- utils.meta_attr('interpolation'), default="false", recursive=True)
-
-class Parser(chameleon.zpt.language.Parser):
- """Zope Page Template parser."""
-
- element_mapping = {
- config.XHTML_NS: {None: XHTMLElement},
- config.META_NS: {None: MetaElement},
- config.TAL_NS: {None: TALElement},
- config.METAL_NS: {None: METALElement}}
-
- fallback = XHTMLElement
- default_expression = 'path'
Modified: z3c.pt/trunk/src/z3c/pt/loader.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/loader.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/loader.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -2,14 +2,14 @@
import os.path
from z3c.pt.pagetemplate import PageTemplateFile
-from z3c.pt.texttemplate import TextTemplateFile
+# from z3c.pt.texttemplate import TextTemplateFile
-from chameleon.core import loader
+from chameleon import loader
class TemplateLoader(loader.TemplateLoader):
def load_page(self, filename):
return self.load(filename, PageTemplateFile)
- def load_text(self, filename):
- return self.load(filename, TextTemplateFile)
+ #def load_text(self, filename):
+ # return self.load(filename, TextTemplateFile)
Modified: z3c.pt/trunk/src/z3c/pt/pagetemplate.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/pagetemplate.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/pagetemplate.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -1,21 +1,23 @@
import os
+import ast
import sys
-import compiler
+from functools import partial
from zope import i18n
-from zope import component
-from chameleon.core import types
-from chameleon.core import config
-from chameleon.core import codegen
-from chameleon.core import clauses
-from chameleon.core import generation
-from chameleon.core import utils
-from chameleon.core.i18n import fast_translate
+from chameleon.i18n import fast_translate
from chameleon.zpt import template
-from chameleon.zpt.interfaces import IExpressionTranslator
+from chameleon.tales import PythonExpr
+from chameleon.tales import StringExpr
+from chameleon.tales import NotExpr
+from chameleon.astutil import store
+from chameleon.astutil import param
+from chameleon.astutil import load
+from chameleon.codegen import TemplateCodeGenerator
+from chameleon.compiler import ExpressionCompiler
+from chameleon.tales import TalesEngine
-from z3c.pt import language
+from z3c.pt import expressions
try:
from Missing import MV
@@ -26,7 +28,8 @@
_marker = object()
_expr_cache = {}
-class opaque_dict(dict):
+
+class OpaqueDict(dict):
def __new__(cls, dictionary):
inst = dict.__new__(cls)
inst.dictionary = dictionary
@@ -43,71 +46,25 @@
def __repr__(self):
return "{...} (%d entries)" % len(self)
-sys_modules = opaque_dict(sys.modules)
+sys_modules = OpaqueDict(sys.modules)
-def evaluate_expression(pragma, expr):
- key = "%s(%s)" % (pragma, expr)
- try:
- symbol_mapping, parts, source = _expr_cache[key]
- except KeyError:
- translator = component.getUtility(IExpressionTranslator, name=pragma)
- parts = translator.tales(expr)
- stream = generation.CodeIO(symbols=config.SYMBOLS)
- assign = clauses.Assign(parts, 'result')
- assign.begin(stream)
- assign.end(stream)
- source = stream.getvalue()
- symbol_mapping = parts.symbol_mapping.copy()
- if isinstance(parts, types.parts):
- for value in parts:
- symbol_mapping.update(value.symbol_mapping)
-
- _expr_cache[key] = symbol_mapping, parts, source
-
- # acquire template locals and update with symbol mapping
- frame = sys._getframe()
- while frame.f_locals.get('econtext', _marker) is _marker:
- frame = frame.f_back
- if frame is None:
- raise RuntimeError, "Can't locate template frame."
-
- _locals = frame.f_locals
- _locals.update(symbol_mapping)
- _locals.update(_locals['econtext'])
-
- # to support dynamic scoping (like in templates), we must
- # transform the code to take the scope locals into account; for
- # efficiency, this is cached for reuse
- code_cache_key = key, tuple(_locals)
-
- try:
- code = _expr_cache[code_cache_key]
- except KeyError:
- suite = codegen.Suite(source, _locals)
- code = compiler.compile(
- suite.source, 'dynamic_path_expression.py', 'exec')
- _expr_cache[code_cache_key] = code
-
- # execute code and return evaluation
- _locals[config.SYMBOLS.lookup_attr] = codegen.lookup_attr
- exec code in _locals
- return _locals['result']
-
-def evaluate_path(expr):
- return evaluate_expression('path', expr)
-
-def evaluate_exists(expr):
- try:
- return evaluate_expression('exists', expr)
- except NameError:
- return False
-
class BaseTemplate(template.PageTemplate):
content_type = None
- default_parser = language.Parser()
version = 2
+ expression_types = {
+ 'python': PythonExpr,
+ 'string': StringExpr,
+ 'not': NotExpr,
+ 'exists': expressions.ExistsExpr,
+ 'path': expressions.PathExpr,
+ 'provider': expressions.ProviderExpr,
+ 'nocall': expressions.NocallExpr,
+ }
+
+ default_expression = "path"
+
def bind(self, ob=None, request=None, macro=None, global_scope=True):
def render(target_language=None, request=request, **kwargs):
context = self._pt_get_context(ob, request, kwargs)
@@ -122,11 +79,13 @@
target_language = None
context['target_language'] = target_language
- context['econtext'] = utils.econtext(context)
+ context['path'] = partial(self.evaluate_path, econtext=context)
+ context['exists'] = partial(self.evaluate_exists, econtext=context)
# bind translation-method to request
def translate(
- msgid, domain=None, mapping=None, target_language=None, default=None):
+ msgid, domain=None, mapping=None,
+ target_language=None, default=None):
if msgid is MV:
# Special case handling of Zope2's Missing.MV
# (Missing.Value) used by the ZCatalog but is
@@ -134,7 +93,7 @@
return
return fast_translate(
msgid, domain, mapping, request, target_language, default)
- context[config.SYMBOLS.translate] = translate
+ context["translate"] = translate
if request is not None and not isinstance(request, basestring):
content_type = self.content_type or 'text/html'
@@ -143,11 +102,7 @@
response.setHeader(
"Content-Type", content_type)
- if macro is None:
- return self.render(**context)
- else:
- return self.render_macro(
- macro, global_scope=global_scope, parameters=context)
+ return "".join(self.render(**context))
return BoundPageTemplate(self, render)
@@ -159,15 +114,61 @@
return dict(
options=kwargs,
request=request,
- path=evaluate_path,
- exists=evaluate_exists,
nothing=None,
- modules=sys_modules)
+ modules=sys_modules
+ )
+ def evaluate_expression(self, pragma, expr, econtext):
+ key = "%s(%s)" % (pragma, expr)
+
+ try:
+ function = _expr_cache[key]
+ except KeyError:
+ compiler = ExpressionCompiler(self.engine, {})
+ target = store("_result")
+ body = compiler("%s:%s" % (pragma, expr), target)
+ body.append(ast.Return(load("_result")))
+
+ fdef = ast.FunctionDef("_evaluate", ast.arguments(
+ [param("econtext")], None, None, []), body, [])
+
+ module = ast.Module([fdef])
+ ast.fix_missing_locations(module)
+
+ generator = TemplateCodeGenerator(module)
+
+ d = {}
+ exec generator.code in d
+ function = _expr_cache[key] = d[fdef.name]
+
+ if econtext is None:
+ # acquire template locals and update with symbol mapping
+ frame = sys._getframe()
+ while frame.f_locals.get('econtext', _marker) is _marker:
+ frame = frame.f_back
+ if frame is None:
+ raise RuntimeError("Can't locate template frame.")
+
+ econtext = frame.f_locals
+
+ return function(econtext)
+
+ def evaluate_path(self, expr, econtext=None):
+ return self.evaluate_expression('path', expr, econtext)
+
+ def evaluate_exists(self, expr, econtext=None):
+ try:
+ return self.evaluate_expression('exists', expr, econtext)
+ except NameError:
+ return False
+
+
class BaseTemplateFile(BaseTemplate, template.PageTemplateFile):
"""If ``filename`` is a relative path, the module path of the
class where the instance is used to get an absolute path."""
+ cache = {}
+
def __init__(self, filename, path=None, content_type=None, **kwargs):
if path is not None:
filename = os.path.join(path, filename)
@@ -176,7 +177,8 @@
for depth in (1, 2):
frame = sys._getframe(depth)
package_name = frame.f_globals.get('__name__', None)
- if package_name is not None and package_name != self.__module__:
+ if package_name is not None and \
+ package_name != self.__module__:
module = sys.modules[package_name]
try:
path = module.__path__[0]
@@ -200,6 +202,7 @@
# magically sniffed from the source template.
self.content_type = content_type
+
class PageTemplate(BaseTemplate):
"""Page Templates using TAL, TALES, and METAL.
@@ -215,6 +218,7 @@
return self.bind(instance)
return self
+
class PageTemplateFile(BaseTemplateFile, PageTemplate):
"""Page Templates using TAL, TALES, and METAL.
@@ -223,6 +227,9 @@
Initialize with a filename."""
+ cache = {}
+
+
class ViewPageTemplate(PageTemplate):
"""Template class suitable for use with a Zope browser view; the
variables ``view``, ``context`` and ``request`` variables are
@@ -240,11 +247,10 @@
view=view,
context=context,
request=request,
- path=evaluate_path,
- exists=evaluate_exists,
options=kwargs,
nothing=None,
- modules=sys_modules)
+ modules=sys_modules
+ )
def __call__(self, _ob=None, context=None, request=None, **kwargs):
kwargs.setdefault('context', context)
@@ -252,10 +258,14 @@
bound_pt = self.bind(_ob)
return bound_pt(**kwargs)
+
class ViewPageTemplateFile(ViewPageTemplate, PageTemplateFile):
"""If ``filename`` is a relative path, the module path of the
class where the instance is used to get an absolute path."""
+ cache = {}
+
+
class BoundPageTemplate(object):
"""When a page template class is used as a property, it's bound to
the class instance on access, which is implemented using this
Modified: z3c.pt/trunk/src/z3c/pt/tests/test_doctests.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/test_doctests.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/tests/test_doctests.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -8,18 +8,16 @@
import zope.configuration.xmlconfig
import z3c.pt
-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 = 'README.txt',
testsuites = 'z3c.pt.expressions', 'z3c.pt.namespaces'
- config.DISK_CACHE = False
-
return unittest.TestSuite(
[doctest.DocFileSuite(
filesuite, optionflags=OPTIONFLAGS,
Modified: z3c.pt/trunk/src/z3c/pt/tests/test_loader.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/tests/test_loader.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/tests/test_loader.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -44,10 +44,10 @@
def _load(self, loader, filename):
return loader.load_page(filename)
-class LoadTextTests(unittest.TestCase, LoadTests):
- def _load(self, loader, filename):
- return loader.load_text(filename)
-
+# class LoadTextTests(unittest.TestCase, LoadTests):
+# def _load(self, loader, filename):
+# return loader.load_text(filename)
+
def test_suite():
import sys
return unittest.findTestCases(sys.modules[__name__])
Deleted: z3c.pt/trunk/src/z3c/pt/texttemplate.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/texttemplate.py 2011-02-21 00:02:43 UTC (rev 120483)
+++ z3c.pt/trunk/src/z3c/pt/texttemplate.py 2011-02-21 09:01:02 UTC (rev 120484)
@@ -1,34 +0,0 @@
-from chameleon.core import config
-
-import chameleon.zpt.language
-import pagetemplate
-
-class XHTMLElement(chameleon.zpt.language.XHTMLElement):
- meta_interpolation_escaping = False
-
-class Parser(chameleon.zpt.language.Parser):
- default_expression = "path"
-
- element_mapping = {
- config.META_NS: {None: XHTMLElement},
- }
-
-class TextTemplate(pagetemplate.PageTemplate):
- __doc__ = pagetemplate.PageTemplate.__doc__ # for Sphinx autodoc
- default_parser = Parser()
- format = 'text'
-
-class TextTemplateFile(pagetemplate.PageTemplateFile):
- __doc__ = pagetemplate.PageTemplateFile.__doc__ # for Sphinx autodoc
- default_parser = Parser()
- format = 'text'
-
-class ViewTextTemplate(pagetemplate.ViewPageTemplate):
- __doc__ = pagetemplate.ViewPageTemplate.__doc__ # for Sphinx autodoc
- default_parser = Parser()
- format = 'text'
-
-class ViewTextTemplateFile(pagetemplate.ViewPageTemplateFile):
- __doc__ = pagetemplate.ViewPageTemplateFile.__doc__ # for Sphinx autodoc
- default_parser = Parser()
- format = 'text'
More information about the checkins
mailing list