[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('<foo></bar>' 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('<foo></bar>' 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