[Checkins] SVN: five.pt/trunk/ Upgrade to latest ``z3c.pt``, fixing a number of issues.

Malthe Borch mborch at gmail.com
Sun Jan 8 16:36:04 UTC 2012


Log message for revision 123989:
  Upgrade to latest ``z3c.pt``, fixing a number of issues.

Changed:
  U   five.pt/trunk/CHANGES.txt
  U   five.pt/trunk/setup.py
  U   five.pt/trunk/src/five/pt/expressions.py

-=-
Modified: five.pt/trunk/CHANGES.txt
===================================================================
--- five.pt/trunk/CHANGES.txt	2012-01-08 16:32:21 UTC (rev 123988)
+++ five.pt/trunk/CHANGES.txt	2012-01-08 16:36:03 UTC (rev 123989)
@@ -3,6 +3,20 @@
 
 In next release ...
 
+Features:
+
+- Whitespace between attributes is now reduced to a single whitespace
+  character.
+
+Bugfixes:
+
+- The path traverser now correctly renders callables, applying the
+  template namespace as keyword arguments. Previously, only the
+  ``request`` name would be passed.
+
+- The content provider expression now correctly applies TAL namespace
+  data.
+
 - Avoid duplicate HTML decoding. This fixes an issue which was
   introduced because newer Chameleon releases decode all expression
   inputs by default.

Modified: five.pt/trunk/setup.py
===================================================================
--- five.pt/trunk/setup.py	2012-01-08 16:32:21 UTC (rev 123988)
+++ five.pt/trunk/setup.py	2012-01-08 16:36:03 UTC (rev 123989)
@@ -1,6 +1,6 @@
 from setuptools import setup, find_packages
 
-version = '2.2.0'
+version = '2.2.1'
 
 setup(name='five.pt',
       version=version,
@@ -26,7 +26,7 @@
       install_requires=[
           'setuptools',
           'sourcecodegen>=0.6.14',
-          'z3c.pt>=2.1.4',
+          'z3c.pt>=2.2',
           'zope.pagetemplate>=3.6.2',
       ],
       entry_points="""

Modified: five.pt/trunk/src/five/pt/expressions.py
===================================================================
--- five.pt/trunk/src/five/pt/expressions.py	2012-01-08 16:32:21 UTC (rev 123988)
+++ five.pt/trunk/src/five/pt/expressions.py	2012-01-08 16:36:03 UTC (rev 123989)
@@ -2,22 +2,30 @@
 from types import ClassType
 from compiler import parse as ast24_parse
 
-from Acquisition import aq_base
 from OFS.interfaces import ITraversable
-from Products.PageTemplates import ZRPythonExpr
 from zExceptions import NotFound, Unauthorized
 
-from zope import component
-from zope.proxy import removeAllProxies
-from zope.traversing.adapters import traversePathElement
-from zope.traversing.interfaces import TraversalError
+from zope.component import queryMultiAdapter
 from zope.contentprovider.interfaces import IContentProvider
 from zope.contentprovider.interfaces import ContentProviderLookupError
+from zope.contentprovider.tales import addTALNamespaceData
 
+try:
+    from zope.contentprovider.interfaces import BeforeUpdateEvent
+except ImportError:
+    BeforeUpdateEvent = None
+
+from zope.event import notify
+from zope.location.interfaces import ILocation
+from zope.traversing.adapters import traversePathElement
+from zope.traversing.interfaces import TraversalError
+
 from RestrictedPython.RestrictionMutator import RestrictionMutator
 from RestrictedPython.Utilities import utility_builtins
 from RestrictedPython import MutatingWalker
 
+from Products.PageTemplates.Expressions import render
+
 from AccessControl.ZopeGuards import guarded_getattr
 from AccessControl.ZopeGuards import guarded_getitem
 from AccessControl.ZopeGuards import guarded_apply
@@ -34,12 +42,51 @@
 _marker = object()
 
 try:
-    import Products.Five.browser.providerexpression
-    AQ_WRAP_CP = True
+    # If this import succeeds, we need to use a content provider
+    # renderer which acquisition-wraps the provider component
+    from Products.Five.browser import providerexpression
+    providerexpression
+
 except ImportError:
-    AQ_WRAP_CP = False
+    ProviderExpr = expressions.ProviderExpr
+else:
+    def render_content_provider(econtext, name):
+        name = name.strip()
 
+        context = econtext.get('context')
+        request = econtext.get('request')
+        view = econtext.get('view')
 
+        cp = queryMultiAdapter(
+            (context, request, view), IContentProvider, name=name)
+
+        # provide a useful error message, if the provider was not found.
+        if cp is None:
+            raise ContentProviderLookupError(name)
+
+        # add the __name__ attribute if it implements ILocation
+        if ILocation.providedBy(cp):
+            cp.__name__ = name
+
+        # Insert the data gotten from the context
+        addTALNamespaceData(cp, econtext)
+
+        # BBB: This is where we're different:
+        if getattr(cp, '__of__', None) is not None:
+            cp = cp.__of__(context)
+
+        # Stage 1: Do the state update.
+        if BeforeUpdateEvent is not None:
+            notify(BeforeUpdateEvent(cp, request))
+        cp.update()
+
+        # Stage 2: Render the HTML content.
+        return cp.render()
+
+    class ProviderExpr(expressions.ProviderExpr):
+        transform = Symbol(render_content_provider)
+
+
 zope2_exceptions = NameError, \
                    ValueError, \
                    AttributeError, \
@@ -54,35 +101,6 @@
     return Static(template("obj", obj=Symbol(obj), mode="eval"))
 
 
-def render(ob, request):
-    """Calls the object, possibly a document template, or just returns
-    it if not callable.  (From Products.PageTemplates.Expressions.py)
-    """
-    # We are only different in the next line. The original function gets a
-    # dict-ish namespace passed in, we fake it.
-    # ZRPythonExpr.call_with_ns expects to get such a dict
-    ns = dict(context=ob, request=request)
-
-    if hasattr(ob, '__render_with_namespace__'):
-        ob = ZRPythonExpr.call_with_ns(ob.__render_with_namespace__, ns)
-    else:
-        # items might be acquisition wrapped
-        base = aq_base(ob)
-        # item might be proxied (e.g. modules might have a deprecation
-        # proxy)
-        base = removeAllProxies(base)
-        if callable(base):
-            try:
-                if getattr(base, 'isDocTemp', 0):
-                    ob = ZRPythonExpr.call_with_ns(ob, ns, 2)
-                else:
-                    ob = ob()
-            except AttributeError, n:
-                if str(n) != '__call__':
-                    raise
-    return ob
-
-
 class BoboAwareZopeTraverse(object):
     traverse_method = 'restrictedTraverse'
 
@@ -110,14 +128,17 @@
 
         return base
 
-    def __call__(self, base, request, call, *path_items):
-        base = self.traverse(base, request, path_items)
+    def __call__(self, base, econtext, call, path_items):
+        request = econtext.get('request')
 
+        if path_items:
+            base = self.traverse(base, request, path_items)
+
         if call is False:
             return base
 
         if getattr(base, '__call__', _marker) is not _marker or callable(base):
-            base = render(base, request)
+            base = render(base, econtext)
 
         return base
 
@@ -127,7 +148,9 @@
 
     __slots__ = ()
 
-    def __call__(self, base, request, call, *path_items):
+    def __call__(self, base, econtext, call, path_items):
+        request = econtext.get('request')
+
         base = self.traverse(base, request, path_items)
 
         if call is False:
@@ -162,28 +185,6 @@
     exceptions = zope2_exceptions
 
 
-class ContentProviderTraverser(object):
-    def __call__(self, context, request, view, name):
-        cp = component.queryMultiAdapter(
-            (context, request, view), IContentProvider, name=name)
-
-        # provide a useful error message, if the provider was not found.
-        if cp is None:
-            raise ContentProviderLookupError(name)
-
-        if AQ_WRAP_CP and getattr(cp, '__of__', None) is not None:
-            cp = cp.__of__(context)
-
-        cp.update()
-        return cp.render()
-
-
-class ProviderExpr(expressions.ProviderExpr):
-    traverser = Static(
-        template("cls()", cls=Symbol(ContentProviderTraverser), mode="eval")
-        )
-
-
 class RestrictionTransform(NodeTransformer):
     secured = {
         '_getattr_': guarded_getattr,



More information about the checkins mailing list