[Checkins] SVN: five.pt/trunk/ Major architectural change; we no longer provide custom template classes, but patch on a much lower level, effectively replacing the TAL interpreter with a TAL compiler. Note that this change makes additional layers such as ``cmf.pt`` obsolete.

Malthe Borch mborch at gmail.com
Wed Jul 13 12:51:03 EDT 2011


Log message for revision 122180:
  Major architectural change; we no longer provide custom template classes, but patch on a much lower level, effectively replacing the TAL interpreter with a TAL compiler. Note that this change makes additional layers such as ``cmf.pt`` obsolete.

Changed:
  U   five.pt/trunk/CHANGES.txt
  U   five.pt/trunk/README.txt
  U   five.pt/trunk/setup.py
  U   five.pt/trunk/src/five/pt/__init__.py
  U   five.pt/trunk/src/five/pt/configure.zcml
  U   five.pt/trunk/src/five/pt/expressions.py
  U   five.pt/trunk/src/five/pt/meta.zcml
  D   five.pt/trunk/src/five/pt/pagetemplate.py
  U   five.pt/trunk/src/five/pt/patches.py
  U   five.pt/trunk/src/five/pt/tests/locals_base.pt
  D   five.pt/trunk/src/five/pt/tests/test_basetemplatefile.py
  D   five.pt/trunk/src/five/pt/tests/test_doctests.py
  A   five.pt/trunk/src/five/pt/tests/test_pagetemplate.py
  U   five.pt/trunk/src/five/pt/tests/test_patches.py
  U   five.pt/trunk/src/five/pt/tests/test_persistenttemplate.py
  U   five.pt/trunk/src/five/pt/tests/test_viewpagetemplatefile.py
  D   five.pt/trunk/src/five/pt/zcml.py
  D   five.pt/trunk/src/five/pt/zcml.txt

-=-
Modified: five.pt/trunk/CHANGES.txt
===================================================================
--- five.pt/trunk/CHANGES.txt	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/CHANGES.txt	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,6 +1,16 @@
 Changelog
 =========
 
+2.1-dev (unreleased)
+~~~~~~~~~~~~~~~~~~~~
+
+- Major architectural change.
+
+  The package no longer contains own template classes; instead,
+  patches are made to switch from the reference TAL interpreter to the
+  Chameleon TAL compiler.
+  [malthe]
+
 2.0-rc3 (2011-07-07)
 ~~~~~~~~~~~~~~~~~~~~
 

Modified: five.pt/trunk/README.txt
===================================================================
--- five.pt/trunk/README.txt	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/README.txt	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,28 +1,26 @@
 Overview
 ========
 
-The five.pt package brings the Chameleon template engine to the Zope 2
-platform. It's a drop-in replacement, providing bridges to the most
-common API.
+This package brings the Chameleon template engine to the Zope 2
+platform. Five is supported.
 
-Support for browser pages, viewlets and viewlet managers is included.
+It works using monkey-patching onto the existing API (specifically,
+the ``TALInterpreter`` and ``PageTemplate`` classes). In simple terms,
+what the patching does is to replace the TAL interpreter class and
+make sure that the so-called "cooking" routine uses the Chameleon
+parser and compiler instead of the ``zope.*`` reference
+implementation.
 
+
 Usage
 ~~~~~
 
-To enable Chameleon, simply include the ZCML configuration::
+To enable Chameleon, configure the package using ZCML::
 
   <include package="five.pt" />
 
-Tempates may be instantiated directly. Here's an example of a browser view
-which uses a view page template::
+Alternatively, import the ``patches`` module at any time::
 
-  from Products.Five import BrowserView
-  from five.pt.pagetemplate import ViewPageTemplateFile
+  import five.pt.patches
 
-  class SimpleView(BrowserView):
-      index = ViewPageTemplateFile('simple.pt')
-
-Other template classes are available, see the ``pagetemplate`` module.
-
-For general information about Chameleon, see http://chameleon.repoze.org/.
+For more information on Chameleon, see http://www.pagetemplates.org/.

Modified: five.pt/trunk/setup.py
===================================================================
--- five.pt/trunk/setup.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/setup.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,6 +1,6 @@
 from setuptools import setup, find_packages
 
-version = '2.0-rc3'
+version = '2.1-dev'
 
 setup(name='five.pt',
       version=version,
@@ -25,8 +25,8 @@
       zip_safe=False,
       install_requires=[
           'setuptools',
-          'z3c.pt>=2.0-rc1',
-          'Chameleon>=2.0-rc13',
+          'z3c.pt>=2.0-rc3',
+          'Chameleon>=2.0-rc14',
           'sourcecodegen',
       ],
       entry_points="""

Modified: five.pt/trunk/src/five/pt/__init__.py
===================================================================
--- five.pt/trunk/src/five/pt/__init__.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/__init__.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,20 +1 @@
-import patches
-
-
-def initialize(site):
-    import chameleon.config
-
-    if chameleon.config.EAGER_PARSING:
-        import gc
-
-        # this only deals with the page template classes provided by
-        # Zope, as Chameleon's classes are aware of the eager parsing
-        # flag
-        from zope.pagetemplate.pagetemplatefile import PageTemplateFile
-        from five.pt.pagetemplate import BaseTemplateFile
-
-        for template in (x for x in gc.get_objects()
-                         if isinstance(x, PageTemplateFile)):
-
-            inst = BaseTemplateFile(template.filename)
-            inst.parse()
+#

Modified: five.pt/trunk/src/five/pt/configure.zcml
===================================================================
--- five.pt/trunk/src/five/pt/configure.zcml	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/configure.zcml	2011-07-13 16:51:02 UTC (rev 122180)
@@ -3,8 +3,6 @@
     xmlns:five="http://namespaces.zope.org/five">
 
   <include package="z3c.pt" />
-  <include package="five.pt" file="meta.zcml" />
+  <include package=".patches" />
 
-  <five:registerPackage package="." initialize=".initialize" />
-
 </configure>

Modified: five.pt/trunk/src/five/pt/expressions.py
===================================================================
--- five.pt/trunk/src/five/pt/expressions.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/expressions.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -24,6 +24,7 @@
 
 from chameleon.astutil import Symbol
 from chameleon.astutil import Static
+from chameleon.astutil import NameLookupRewriteVisitor
 from chameleon.codegen import template
 from chameleon.utils import decode_htmlentities
 from sourcecodegen import generate_code
@@ -168,15 +169,24 @@
         return node
 
 
-class PythonExpr(expressions.PythonExpr):
+class SecurePythonExpr(expressions.PythonExpr):
     rm = RestrictionMutator()
     rt = RestrictionTransform()
 
+    def _dynamic_transform(node):
+        if node.id == 'repeat':
+            node.id = 'wrapped_repeat'
+
+        return node
+
+    nt = NameLookupRewriteVisitor(_dynamic_transform)
+
     def parse(self, string):
         decoded = decode_htmlentities(string)
         node = ast24_parse(decoded, 'eval').node
         MutatingWalker.walk(node, self.rm)
         string = generate_code(node)
-        value = super(PythonExpr, self).parse(string)
+        value = super(SecurePythonExpr, self).parse(string)
         self.rt.visit(value)
+        self.nt.visit(value)
         return value

Modified: five.pt/trunk/src/five/pt/meta.zcml
===================================================================
--- five.pt/trunk/src/five/pt/meta.zcml	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/meta.zcml	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,32 +1,5 @@
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    xmlns:meta="http://namespaces.zope.org/meta"
-    xmlns:zcml="http://namespaces.zope.org/zcml">
+<configure xmlns="http://namespaces.zope.org/zope">
 
-  <include package="Products.Five" />
-  
-  <meta:directives namespace="http://namespaces.zope.org/browser">
+  <!-- Nothing here; maintained for compatibility purposes -->
 
-    <!-- browser pages -->
-
-    <meta:directive
-       name="page"
-       schema="zope.app.publisher.browser.metadirectives.IPageDirective"
-       handler=".zcml.page_directive"
-       />
-
-    <meta:directive
-       name="viewlet"
-       schema="zope.viewlet.metadirectives.IViewletDirective"
-       handler=".zcml.viewlet_directive"
-       />
-    
-    <meta:directive
-       name="viewletManager"
-       schema="zope.viewlet.metadirectives.IViewletManagerDirective"
-       handler=".zcml.viewlet_manager_directive"
-       />
-
-  </meta:directives>
-
 </configure>

Deleted: five.pt/trunk/src/five/pt/pagetemplate.py
===================================================================
--- five.pt/trunk/src/five/pt/pagetemplate.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/pagetemplate.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,181 +0,0 @@
-import os
-
-from DateTime import DateTime
-from zope.app.pagetemplate.viewpagetemplatefile import ViewMapper
-from zope.interface import implements
-from zope.pagetemplate.interfaces import IPageTemplate
-
-from Acquisition import aq_get
-from Acquisition import aq_inner
-from Acquisition import aq_parent
-from AccessControl import getSecurityManager
-from App.config import getConfiguration
-
-from Products.PageTemplates.Expressions import SecureModuleImporter
-
-from chameleon.tales import StringExpr
-from chameleon.tales import NotExpr
-from chameleon.tales import PythonExpr
-
-from z3c.pt import pagetemplate
-from z3c.pt import expressions
-
-from .expressions import PathExpr
-from .expressions import ProviderExpr
-from .expressions import NocallExpr
-from .expressions import ExistsExpr
-from .expressions import PythonExpr as SecurePythonExpr
-
-
-EXTRA_CONTEXT_KEY = '__five_pt_extra_context'
-
-
-def get_physical_root(context):
-    method = aq_get(context, 'getPhysicalRoot', None)
-    if method is not None:
-        return method()
-
-
-def same_type(arg1, *args):
-    """Compares the class or type of two or more objects. Copied from
-    RestrictedPython.
-    """
-    t = getattr(arg1, '__class__', type(arg1))
-    for arg in args:
-        if getattr(arg, '__class__', type(arg)) is not t:
-            return False
-    return True
-
-
-def test(condition, a, b):
-    if condition:
-        return a
-    return b
-
-
-class BaseTemplateBase(pagetemplate.BaseTemplate):
-    """Base for Zope 2-compatible page template classes."""
-
-    implements(IPageTemplate)
-
-    utility_builtins = {}
-    encoding = 'utf-8'
-
-    expression_types = {
-        'python': SecurePythonExpr,
-        'string': StringExpr,
-        'not': NotExpr,
-        'exists': ExistsExpr,
-        'path': PathExpr,
-        'provider': ProviderExpr,
-        'nocall': NocallExpr,
-        }
-
-    # We enable template reload setting in application debug-mode
-    if getConfiguration().debug_mode:
-        auto_reload = True
-
-    def render_macro(self, macro, parameters=None, **kw):
-        context = self._pt_get_context(None, None)
-
-        if parameters is not None:
-            context.update(parameters)
-
-        return super(BaseTemplate, self).render_macro(
-            macro, parameters=context, **kw)
-
-    def _pt_get_context(self, instance, request, kwargs={}):
-        extra_context = kwargs.pop(EXTRA_CONTEXT_KEY, {})
-        namespace = dict(self.utility_builtins)
-
-        if instance is not None:
-            # instance namespace overrides utility_builtins
-            context = aq_parent(instance)
-            namespace.update(
-                context=context,
-                request=request or aq_get(instance, 'REQUEST', None),
-                template=self,
-                here=context,
-                container=context,
-                nothing=None,
-                same_type=same_type,
-                test=test,
-                root=get_physical_root(context),
-                user=getSecurityManager().getUser(),
-                modules=SecureModuleImporter,
-                DateTime=DateTime,
-                options=kwargs)
-
-        # extra_context (from pt_render()) overrides the default namespace
-        namespace.update(extra_context)
-
-        return namespace
-
-class BaseTemplate(BaseTemplateBase):
-    """Zope 2-compatible page template class."""
-
-    def __init__(self, body, *args, **kw):
-        super(BaseTemplate, self).__init__(body, *args, **kw)
-        # keep the body for comparison and caching purposes
-        self.body = body
-
-class BaseTemplateFile(BaseTemplateBase, pagetemplate.BaseTemplateFile):
-    """Zope 2-compatible page template file class."""
-
-
-class ViewPageTemplate(pagetemplate.ViewPageTemplate, BaseTemplateBase):
-
-    expression_types = {
-        'python': PythonExpr,
-        'string': StringExpr,
-        'not': NotExpr,
-        'exists': ExistsExpr,
-        'path': PathExpr,
-        'provider': ProviderExpr,
-        'nocall': NocallExpr,
-        }
-
-    encoding = 'UTF-8'
-
-    def _pt_get_context(self, view, request, kwargs):
-        if view is None:
-            namespace = {}
-        else:
-            try:
-                request = request or view.request
-                context = aq_inner(view.context)
-            except AttributeError:
-                """This may happen with certain dynamically created
-                classes,
-                e.g. ``plone.app.form._named.GeneratedClass``.
-                """
-                view = view.context
-                request = view.request
-                context = aq_inner(view.context)
-
-            namespace = dict(
-                context=context,
-                request=request,
-                view=view,
-                template=self,
-                here=context,
-                container=context,
-                nothing=None,
-                root=get_physical_root(context),
-                user=getSecurityManager().getUser(),
-                modules=SecureModuleImporter,
-                views=ViewMapper(context, request),
-                options=kwargs)
-
-        return namespace
-
-
-class ViewPageTemplateFile(ViewPageTemplate,
-                           pagetemplate.ViewPageTemplateFile):
-    """If ``filename`` is a relative path, the module path of the
-    class where the instance is used to get an absolute path."""
-
-    def getId(self):
-        return os.path.basename(self.filename)
-
-    id = property(getId)

Modified: five.pt/trunk/src/five/pt/patches.py
===================================================================
--- five.pt/trunk/src/five/pt/patches.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/patches.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,176 +1,142 @@
-"""Monkey-patching page template classes.
+"""Patch legacy template classes.
 
-Since many templates are instantiated at module-import, we patch using
-a duck-typing strategy.
-
-We replace the ``__get__``-method of the ViewPageTemplateFile class
-(both the Five variant and the base class). This allows us to return a
-Chameleon template instance, transparent to the calling class.
+We patch the ``TALInterpreter`` class as well as the cook-method on
+the pagetemplate base class (which produces the input for the TAL
+interpreter).
 """
 
-from zope.app.pagetemplate.viewpagetemplatefile import (
-    ViewPageTemplateFile as ZopeViewPageTemplateFile)
+import sys
 
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-from Products.PageTemplates.PageTemplateFile import PageTemplate
-from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile as \
-     FiveViewPageTemplateFile
+from zope.tal.talinterpreter import TALInterpreter
+from zope.pagetemplate.pagetemplate import PageTemplate
+from z3c.pt.pagetemplate import PageTemplate as ChameleonPageTemplate
+from z3c.pt.pagetemplate import PageTemplateFile as ChameleonPageTemplateFile
 
-from five.pt.pagetemplate import ViewPageTemplateFile
-from five.pt.pagetemplate import BaseTemplate
-from five.pt.pagetemplate import BaseTemplateFile
-from five.pt.pagetemplate import EXTRA_CONTEXT_KEY
-
-from Acquisition import aq_base
-from Acquisition import aq_parent
-from Acquisition.interfaces import IAcquirer
-from Acquisition import ImplicitAcquisitionWrapper
-
-from ComputedAttribute import ComputedAttribute
 from AccessControl.SecurityInfo import ClassSecurityInfo
 from App.class_init import InitializeClass
+from Products.PageTemplates.Expressions import getEngine
 
-# declare Chameleon's repeatdict public
+from chameleon.tales import StringExpr
+from chameleon.tales import NotExpr
+from chameleon.tales import PythonExpr
 from chameleon.tal import RepeatDict
 
+from .expressions import PathExpr
+from .expressions import ProviderExpr
+from .expressions import NocallExpr
+from .expressions import ExistsExpr
+from .expressions import SecurePythonExpr
+
+
+# Declare Chameleon's repeat dictionary public
 RepeatDict.security = ClassSecurityInfo()
 RepeatDict.security.declareObjectPublic()
 RepeatDict.__allow_access_to_unprotected_subobjects__ = True
 
 InitializeClass(RepeatDict)
 
-try:
-    from Products.Five.browser.pagetemplatefile import BoundPageTemplate
-except ImportError:
-    from zope.app.pagetemplate.viewpagetemplatefile import BoundPageTemplate
-    import Acquisition
+# Zope 2 Page Template expressions
+_secure_expression_types = {
+    'python': SecurePythonExpr,
+    'string': StringExpr,
+    'not': NotExpr,
+    'exists': ExistsExpr,
+    'path': PathExpr,
+    'provider': ProviderExpr,
+    'nocall': NocallExpr,
+    }
 
-    class BoundPageTemplate(BoundPageTemplate, Acquisition.Implicit):
-        """Implementing Acquisition.interfaces.IAcquirer and
-        IAcquisitionWrapper.
-        """
 
-        __parent__ = property(lambda self: self.im_self)
+# Zope 3 Page Template expressions
+_expression_types = {
+    'python': PythonExpr,
+    'string': StringExpr,
+    'not': NotExpr,
+    'exists': ExistsExpr,
+    'path': PathExpr,
+    'provider': ProviderExpr,
+    'nocall': NocallExpr,
+    }
 
-        def __call__(self, im_self=None, *args, **kw):
-            if self.im_self is None:
-                im_self = im_self
-            else:
-                im_self = aq_base(self.im_self)
-                if IAcquirer.providedBy(im_self):
-                    im_self = im_self.__of__(im_self.context)
-            return self.im_func(im_self, *args, **kw)
 
-    class BaseTemplateFile(BaseTemplateFile, Acquisition.Implicit):
-        """Implement Acquisition.interfaces.IAcquirer and
-        IAcquisitionWrapper.
-        """
+def cook(self):
+    engine = self.pt_getEngine()
 
-_marker = object()
+    filename = getattr(self, 'filename', None)
 
+    if engine is getEngine():
+        expression_types = _secure_expression_types
+    else:
+        expression_types = _expression_types
 
-def get_bound_template(self, instance, type):
-    if instance is None:
-        return self
+    if filename is None:
+        program = ChameleonPageTemplate(
+            self._text, keep_body=True,
+            expression_types=expression_types,
+            encoding='utf-8')
+    else:
+        program = ChameleonPageTemplateFile(
+            filename, keep_body=True,
+            expression_types=expression_types,
+            encoding='utf-8')
 
-    template = getattr(self, '_v_template', _marker)
-    if template is _marker:
-        self._v_template = template = ViewPageTemplateFile(self.filename)
+    self._v_program = program
+    self._v_macros = program.macros
+    self._v_cooked = 1
 
-    return BoundPageTemplate(template, instance)
-
-
-def _get_five_pt_template(self):
-    template = getattr(self, '_v_template', _marker)
-    if template is _marker or self._text != template.body:
-        self._v_template = template = BaseTemplate(self._text, keep_source=True)
-
-    return template
-
-def _get_five_pt_template_wrapped(self):
-    template = _get_five_pt_template(self)
-
-    if IAcquirer.providedBy(template):
-        template = template.__of__(aq_parent(self))
+    try:
+        program.cook_check()
+    except:
+        etype, e = sys.exc_info()[:2]
+        self._v_errors = [
+            "Compilation failed",
+            "%s.%s: %s" % (etype.__module__, etype.__name__, e)
+            ]
     else:
-        template = ImplicitAcquisitionWrapper(template, aq_parent(self))
+        self._v_errors = ()
 
-    return template
 
-def call_template(self, *args, **kw):
-    # avoid accidental exposure of the extra context parameter
-    kw.pop(EXTRA_CONTEXT_KEY, None)
-    template = self._get_five_pt_template()
-    return template(self, *args, **kw)
+def test(condition, a, b):
+    if condition:
+        return a
+    return b
 
-def pt_render(self, source=False, extra_context=None):
-    if source:
-        return self._text
-    if extra_context is None:
-        extra_context = {}
-    template = self._get_five_pt_template()
-    return template(self, **{EXTRA_CONTEXT_KEY:extra_context})
 
-def _get_five_pt_template_file_wrapped(self, *args, **kw):
-    template = getattr(self, '_v_template', _marker)
-    if template is _marker:
-        self._v_template = template = BaseTemplateFile(self.filename)
+ at staticmethod
+def create_interpreter(cls, *args, **kwargs):
+    return ChameleonTALInterpreter(*args, **kwargs)
 
-    if IAcquirer.providedBy(template):
-        template = template.__of__(aq_parent(self))
-    else:
-        template = ImplicitAcquisitionWrapper(template, aq_parent(self))
 
-    return template
+class ChameleonTALInterpreter(object):
+    def __init__(self, template, macros, context, stream, tal=True, **kwargs):
+        self.template = template
+        self.econtext = context.vars
+        self.repeat = context.repeat_vars
+        self.stream = stream
+        self.tal = tal
 
+    def __call__(self):
+        if self.tal is False:
+            result = self.template.body
+        else:
+            econtext = self.econtext
 
-def get_macros(self):
-    template = self._get_five_pt_template()
-    return template.macros
+            # Swap out repeat dictionary for Chameleon implementation
+            # and store wrapped dictionary in new variable -- this is
+            # in turn used by the secure Python expression
+            # implementation whenever a 'repeat' symbol is found
+            econtext['wrapped_repeat'] = econtext['repeat']
+            econtext['repeat'] = RepeatDict(self.repeat)
 
-FiveViewPageTemplateFile.__get__ = get_bound_template
-ZopeViewPageTemplateFile.__get__ = get_bound_template
-PageTemplate._get_five_pt_template = _get_five_pt_template
-PageTemplate.__call__ = call_template
-PageTemplate.macros = ComputedAttribute(get_macros, 1)
-PageTemplateFile._get_five_pt_template = _get_five_pt_template_file_wrapped
-PageTemplateFile.__call__ = call_template
-PageTemplateFile.macros = property(get_macros)
-ZopePageTemplate._get_five_pt_template = _get_five_pt_template_wrapped
-ZopePageTemplate._bindAndExec = call_template
-ZopePageTemplate.pt_render = pt_render
-ZopePageTemplate.macros = ComputedAttribute(get_macros, 1)
+            result = self.template.render(
+                path=self.template.evaluate_path,
+                exists=self.template.evaluate_exists,
+                test=test,
+                **econtext
+                )
 
-try:
-    from five.grok.components import ZopeTwoPageTemplate
+        self.stream.write(result)
 
-    class GrokViewAwarePageTemplateFile(ViewPageTemplateFile):
 
-        def pt_getContext(self, instance, request, **kw):
-            return {}
-
-        def _pt_get_context(self, instance, request, kwargs={}):
-            namespace = super(
-                GrokViewAwarePageTemplateFile, self)._pt_get_context(
-                instance, request, kwargs)
-            if hasattr(self, 'pt_grokContext'):
-                namespace.update(self.pt_grokContext)
-            return namespace
-
-        def pt_render(self, namespace):
-            self.pt_grokContext = namespace
-            # namespace contains self.pt_getContext() result + \
-            # five.grok.components.ZopeTwoPageTemplate.getNamespace(view)
-            # result we have currently context, request, static, and
-            # view in the dict
-            view = namespace["view"]
-            return self.__call__(_ob=view)
-            # z3c.pt.pagetemplate.ViewPageTemplate.__call__ will call
-            # self._pt_get_context(ob, None, None)
-
-    def setFromFilename(self, filename, _prefix=None):
-        self._template = GrokViewAwarePageTemplateFile(filename, _prefix)
-    ZopeTwoPageTemplate.setFromFilename = setFromFilename
-except ImportError:
-    pass
+TALInterpreter.__new__ = create_interpreter
+PageTemplate._cook = cook

Modified: five.pt/trunk/src/five/pt/tests/locals_base.pt
===================================================================
--- five.pt/trunk/src/five/pt/tests/locals_base.pt	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/tests/locals_base.pt	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,6 +1,5 @@
 <div xmlns="http://www.w3.org/1999/xhtml"
      xmlns:tal="http://xml.zope.org/namespaces/tal">
-    <div tal:replace="python:'here==context:'+str(here==context)" />
-    <div tal:replace="python:'container==None:'+str(None==container)" />
-    <div tal:replace="string:nothing:${nothing}" />
+    <div tal:replace="python:context" />
+    <div tal:replace="python:container" />
 </div>

Deleted: five.pt/trunk/src/five/pt/tests/test_basetemplatefile.py
===================================================================
--- five.pt/trunk/src/five/pt/tests/test_basetemplatefile.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/tests/test_basetemplatefile.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,57 +0,0 @@
-from Testing.ZopeTestCase import ZopeTestCase
-from five.pt.pagetemplate import BaseTemplateFile
-
-
-class TestPageTemplateFile(ZopeTestCase):
-    def afterSetUp(self):
-        from Products.Five import zcml
-        import Products.Five
-        import z3c.pt
-        import five.pt
-        zcml.load_config("configure.zcml", Products.Five)
-        zcml.load_config("configure.zcml", five.pt)
-        zcml.load_config("configure.zcml", z3c.pt)
-
-    def test_locals_base(self):
-        template = BaseTemplateFile('locals_base.pt')
-        result = template()
-        self.failUnless('here==context:True' in result)
-        self.failUnless('container==None:True' in result)
-        self.failUnless("nothing:" in result)
-
-    def test_nocall(self):
-        template = BaseTemplateFile("nocall.pt")
-
-        def dont_call():
-            raise RuntimeError()
-        result = template(callable=dont_call)
-        self.failUnless(repr(dont_call) in result)
-
-    def test_exists(self):
-        template = BaseTemplateFile("exists.pt")
-
-        def dont_call():
-            raise RuntimeError()
-        result = template(callable=dont_call)
-        self.failUnless('ok' in result)
-
-    def test_simple(self):
-        template = BaseTemplateFile("simple.pt")
-        result = template()
-        self.failUnless('Hello world!' in result)
-
-    def test_secure(self):
-        soup = '<foo></bar>'
-        template = BaseTemplateFile("secure.pt")
-        from zExceptions import Unauthorized
-        try:
-            result = template(soup=soup)
-        except Unauthorized:
-            pass
-        else:
-            self.fail("Expected unauthorized.")
-
-        from AccessControl.SecurityInfo import allow_module
-        allow_module("cgi")
-        result = template(soup=soup)
-        self.failUnless('&lt;foo&gt;&lt;/bar&gt;' in result)

Deleted: five.pt/trunk/src/five/pt/tests/test_doctests.py
===================================================================
--- five.pt/trunk/src/five/pt/tests/test_doctests.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/tests/test_doctests.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,53 +0,0 @@
-import zope.interface
-import zope.component
-
-import os
-import unittest
-import doctest
-
-OPTIONFLAGS = (doctest.ELLIPSIS |
-               doctest.NORMALIZE_WHITESPACE)
-
-import zope.component.testing
-import zope.configuration.xmlconfig
-
-import z3c.pt
-import five.pt
-
-
-class TestParticipation(object):
-    principal = 'foobar'
-    interaction = None
-
-
-def setUp(test):
-    zope.component.testing.setUp(test)
-    zope.configuration.xmlconfig.XMLConfig('meta.zcml', five.pt)()
-    zope.configuration.xmlconfig.XMLConfig('configure.zcml', z3c.pt)()
-
-
-def tearDown(test):
-    zope.component.testing.tearDown(test)
-
-
-def test_suite():
-    import five.pt.tests
-    path = five.pt.tests.__path__[0]
-
-    globs = dict(
-        os=os,
-        path=path,
-        interface=zope.interface,
-        component=zope.component)
-
-    return unittest.TestSuite([
-        doctest.DocFileSuite(
-        "zcml.txt",
-        optionflags=OPTIONFLAGS,
-        globs=globs,
-        setUp=setUp,
-        tearDown=tearDown,
-        package="five.pt")])
-
-if __name__ == '__main__':
-    unittest.main(defaultTest='test_suite')

Copied: five.pt/trunk/src/five/pt/tests/test_pagetemplate.py (from rev 122120, five.pt/trunk/src/five/pt/tests/test_basetemplatefile.py)
===================================================================
--- five.pt/trunk/src/five/pt/tests/test_pagetemplate.py	                        (rev 0)
+++ five.pt/trunk/src/five/pt/tests/test_pagetemplate.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -0,0 +1,63 @@
+import os
+
+from Testing.ZopeTestCase import ZopeTestCase
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+path = os.path.dirname(__file__)
+
+
+class TestPageTemplateFile(ZopeTestCase):
+    def afterSetUp(self):
+        from Products.Five import zcml
+        import Products.Five
+        import z3c.pt
+        import five.pt
+        zcml.load_config("configure.zcml", Products.Five)
+        zcml.load_config("configure.zcml", five.pt)
+        zcml.load_config("configure.zcml", z3c.pt)
+
+    def _makeOne(self, name):
+        return PageTemplateFile(os.path.join(path, name)).\
+               __of__(self.app)
+
+    def test_locals_base(self):
+        template = self._makeOne('locals_base.pt')
+        result = template()
+        self.failUnless('Application' in result)
+
+    def test_nocall(self):
+        template = self._makeOne("nocall.pt")
+
+        def dont_call():
+            raise RuntimeError()
+        result = template(callable=dont_call)
+        self.failUnless(repr(dont_call) in result)
+
+    def test_exists(self):
+        template = self._makeOne("exists.pt")
+
+        def dont_call():
+            raise RuntimeError()
+        result = template(callable=dont_call)
+        self.failUnless('ok' in result)
+
+    def test_simple(self):
+        template = self._makeOne("simple.pt")
+        result = template()
+        self.failUnless('Hello world!' in result)
+
+    def test_secure(self):
+        soup = '<foo></bar>'
+        template = self._makeOne("secure.pt")
+        from zExceptions import Unauthorized
+        try:
+            result = template(soup=soup)
+        except Unauthorized:
+            pass
+        else:
+            self.fail("Expected unauthorized.")
+
+        from AccessControl.SecurityInfo import allow_module
+        allow_module("cgi")
+        result = template(soup=soup)
+        self.failUnless('&lt;foo&gt;&lt;/bar&gt;' in result)

Modified: five.pt/trunk/src/five/pt/tests/test_patches.py
===================================================================
--- five.pt/trunk/src/five/pt/tests/test_patches.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/tests/test_patches.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -11,7 +11,7 @@
         from Products.Five import zcml
         import Products.Five
         import z3c.pt
-        import five.pt.patches
+        import five.pt
         zcml.load_config("configure.zcml", Products.Five)
         zcml.load_config("configure.zcml", five.pt)
         zcml.load_config("configure.zcml", z3c.pt)

Modified: five.pt/trunk/src/five/pt/tests/test_persistenttemplate.py
===================================================================
--- five.pt/trunk/src/five/pt/tests/test_persistenttemplate.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/tests/test_persistenttemplate.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -120,14 +120,14 @@
                          _marker)
         macro_template.macros
 
-        template_compiled = template._v_template
-        macro_template_compiled = macro_template._v_template
+        template_compiled = template._v_program
+        macro_template_compiled = macro_template._v_program
 
         # but they should not be recompiled afterwards
         template()
         macro_template.macros
-        self.assertTrue(template_compiled is template._v_template)
-        self.assertTrue(macro_template_compiled is macro_template._v_template)
+        self.assertTrue(template_compiled is template._v_program)
+        self.assertTrue(macro_template_compiled is macro_template._v_program)
 
     def test_repeat_object_security(self):
         template = self._makeOne('foo', repeat_object)

Modified: five.pt/trunk/src/five/pt/tests/test_viewpagetemplatefile.py
===================================================================
--- five.pt/trunk/src/five/pt/tests/test_viewpagetemplatefile.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/tests/test_viewpagetemplatefile.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -3,7 +3,7 @@
 from Products.Five import BrowserView
 from Testing.ZopeTestCase import ZopeTestCase
 
-from five.pt.pagetemplate import ViewPageTemplateFile
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 
 
 class SimpleView(BrowserView):

Deleted: five.pt/trunk/src/five/pt/zcml.py
===================================================================
--- five.pt/trunk/src/five/pt/zcml.py	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/zcml.py	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,104 +0,0 @@
-import sys
-
-from zope.interface import classImplements
-from zope.configuration.config import ConfigurationMachine
-from zope.component import zcml
-from zope.viewlet.interfaces import IViewletManager
-
-from Products.Five.viewlet import viewlet
-from Products.Five.viewlet import manager
-
-from Products.Five.viewlet import metaconfigure as viewletmeta
-from Products.Five.browser import metaconfigure as viewmeta
-
-from five.pt.pagetemplate import ViewPageTemplateFile
-
-
-def SimpleViewClass(src, offering=None, used_for=None, bases=(), name=u''):
-    if offering is None:
-        offering = sys._getframe(1).f_globals
-
-    bases += (viewmeta.ViewMixinForTemplates,)
-
-    class_ = type("SimpleViewClass from %s" % src, bases,
-                  {'index': ViewPageTemplateFile(src, offering),
-                   '__name__': name})
-
-    if used_for is not None:
-        class_.__used_for__ = used_for
-
-    return class_
-
-
-def SimpleViewletClass(src, offering=None, bases=(), attributes=None,
-                       name=u''):
-    if offering is None:
-        offering = sys._getframe(1).f_globals
-
-    # Create the base class hierarchy
-    bases += (viewlet.simple, viewlet.ViewletBase)
-
-    attrs = {'index': ViewPageTemplateFile(src, offering),
-             '__name__': name}
-    if attributes:
-        attrs.update(attributes)
-
-    # Generate a derived view class.
-    class_ = type("SimpleViewletClass from %s" % src, bases, attrs)
-
-    return class_
-
-
-def page_directive(_context, name, *args, **kwargs):
-    class_ = kwargs.get('class_')
-    template = kwargs.get('template')
-
-    if template:
-        bases = class_ and (class_,) or ()
-        kwargs['class_'] = SimpleViewClass(
-            str(template), bases=bases, name=name)
-        del kwargs['template']
-
-    return viewmeta.page(_context, name, *args, **kwargs)
-
-
-def viewlet_directive(_context, name, *args, **kwargs):
-    class_ = kwargs.get('class_')
-    template = kwargs.get('template')
-
-    if template:
-        bases = class_ and (class_,) or ()
-        kwargs['class_'] = SimpleViewletClass(
-            str(template), bases=bases, name=name)
-        del kwargs['template']
-
-    return viewletmeta.viewletDirective(_context, name, *args, **kwargs)
-
-
-def viewlet_manager_directive(_context, name, *args, **kwargs):
-    template = kwargs.pop('template', None)
-    provides = kwargs.setdefault('provides', IViewletManager)
-    class_ = kwargs.get('class_')
-
-    if template is None:
-        return viewletmeta.viewletManagerDirective(
-            _context, name, *args, **kwargs)
-
-    _new = ConfigurationMachine()
-    viewletmeta.viewletManagerDirective(_new, name, *args, **kwargs)
-
-    for action in _new.actions:
-        try:
-            discriminator, handler, args = action
-            try:
-                name = discriminator.__getitem__(0)
-            except (AttributeError, IndexError):
-                continue
-
-            if name == 'viewletManager':
-                assert handler is zcml.handler, \
-                       "Unsupported action handler '%s'." % repr(handler)
-                new_class = args[1]
-                new_class.template = ViewPageTemplateFile(template)
-        finally:
-            _context.actions.append(action)

Deleted: five.pt/trunk/src/five/pt/zcml.txt
===================================================================
--- five.pt/trunk/src/five/pt/zcml.txt	2011-07-13 16:42:34 UTC (rev 122179)
+++ five.pt/trunk/src/five/pt/zcml.txt	2011-07-13 16:51:02 UTC (rev 122180)
@@ -1,165 +0,0 @@
-Directives
-==========
-
-We'll use a configuration machine to carry out actions; note that when
-actions are executed, the configuration machine is emptied.
-
-  >>> from zope.configuration import config
-  >>> context = config.ConfigurationMachine()
-
-Pages
------
-  
-  >>> from five.pt import zcml
-  >>> zcml.page_directive(
-  ...    context, "test1", "zope2.View", None,
-  ...    template=os.path.join(path, "test.pt"))
-  
-  >>> context.execute_actions()
-
-Verify that page has been registered as a component.
-  
-  >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
-  >>> factory = component.getSiteManager().adapters.lookup(
-  ...     (interface.Interface, IDefaultBrowserLayer),
-  ...     interface.Interface, name="test1")
-
-  >>> factory.index
-  <ViewPageTemplateFile .../test.pt>
-
-We can base the view on an existing class.
-  
-  >>> class View(object):
-  ...     pass
-
-  >>> zcml.page_directive(
-  ...    context, "test2", "zope2.View", None,
-  ...    class_=View, template=os.path.join(path, "test.pt"))
-  
-  >>> context.execute_actions()
-
-  >>> factory = component.getSiteManager().adapters.lookup(
-  ...     (interface.Interface, IDefaultBrowserLayer),
-  ...     interface.Interface, name="test2")
-
-  >>> factory.index
-  <ViewPageTemplateFile .../test.pt>
-
-  >>> issubclass(factory, View)
-  True
-
-Our views will often get utf-8 encoded strings from Zope. They must be
-able to handle that. The PageTemplate class has an attribute encoding, that
-is being used for decoding strings.
-
-  >>> factory.index.encoding
-  'UTF-8'
-
-If the ``__call__`` attribute is set to a template, calling the view will
-render the template.
-
-  >>> from five.pt.pagetemplate import ViewPageTemplateFile
-  
-  >>> class View(object):
-  ...     __call__ = ViewPageTemplateFile(os.path.join(path, "test.pt"))
-
-  >>> zcml.page_directive(
-  ...    context, "test3", "zope2.View", None, class_=View)
-  
-  >>> context.execute_actions()
-
-  >>> factory = component.getSiteManager().adapters.lookup(
-  ...     (interface.Interface, IDefaultBrowserLayer),
-  ...     interface.Interface, name="test3")
-
-  >>> factory.__call__
-  <ViewPageTemplateFile .../test.pt>
-
-  >>> issubclass(factory, View)
-  True
-
-Viewlet managers
-----------------
-
-  >>> zcml.viewlet_manager_directive(
-  ...    context, "test1", "zope2.View",
-  ...    template=os.path.join(path, "test.pt"))
-  
-  >>> context.execute_actions()
-
-Verify that page has been registered as a component.
-  
-  >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
-  >>> from zope.publisher.interfaces.browser import IBrowserView
-  >>> from zope.viewlet.interfaces import IViewletManager
-  
-  >>> factory = component.getSiteManager().adapters.lookup(
-  ...     (interface.Interface, IDefaultBrowserLayer, IBrowserView),
-  ...     IViewletManager, name="test1")
-
-  >>> factory.template
-  <ViewPageTemplateFile .../test.pt>
-
-We can base the viewlet manager on an existing class.
-
-  >>> class ViewletManager(object):
-  ...     pass
-
-  >>> zcml.viewlet_manager_directive(
-  ...    context, "test2", "zope2.View",
-  ...    class_=ViewletManager, template=os.path.join(path, "test.pt"))
-  
-  >>> context.execute_actions()
-
-Verify that page has been registered as a component.
-  
-  >>> factory = component.getSiteManager().adapters.lookup(
-  ...     (interface.Interface, IDefaultBrowserLayer, IBrowserView),
-  ...     IViewletManager, name="test2")
-
-  >>> factory.template
-  <ViewPageTemplateFile .../test.pt>
-
-  >>> issubclass(factory, ViewletManager)
-  True
-
-Viewlets
---------
-
-  >>> zcml.viewlet_directive(
-  ...    context, "test1", "zope2.View",
-  ...    template=os.path.join(path, "test.pt"))
-  
-  >>> context.execute_actions()
-
-Verify that page has been registered as a component.
-  
-  >>> factory = component.getSiteManager().adapters.lookup(
-  ...     (interface.Interface, IDefaultBrowserLayer, IBrowserView, IViewletManager),
-  ...     interface.Interface, name="test1")
-
-  >>> factory.index
-  <ViewPageTemplateFile .../test.pt>
-
-We can base the viewlet on an existing class.
-
-  >>> class Viewlet(object):
-  ...     pass
-
-  >>> zcml.viewlet_directive(
-  ...    context, "test2", "zope2.View",
-  ...    class_=Viewlet, template=os.path.join(path, "test.pt"))
-  
-  >>> context.execute_actions()
-
-Verify that page has been registered as a component.
-  
-  >>> factory = component.getSiteManager().adapters.lookup(
-  ...     (interface.Interface, IDefaultBrowserLayer, IBrowserView, IViewletManager),
-  ...     interface.Interface, name="test2")
-
-  >>> factory.index
-  <ViewPageTemplateFile .../test.pt>
-
-  >>> issubclass(factory, Viewlet)
-  True



More information about the checkins mailing list