[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