Skip to content
This repository has been archived by the owner on May 13, 2020. It is now read-only.

Commit

Permalink
Upgrade to latest z3c.pt, fixing a number of issues.
Browse files Browse the repository at this point in the history
  • Loading branch information
malthe committed Jan 8, 2012
1 parent cee4f64 commit 5fe7f20
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 66 deletions.
14 changes: 14 additions & 0 deletions CHANGES.txt
Expand Up @@ -3,6 +3,20 @@ Changelog

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.
Expand Down
4 changes: 2 additions & 2 deletions setup.py
@@ -1,6 +1,6 @@
from setuptools import setup, find_packages

version = '2.2.0'
version = '2.2.1'

setup(name='five.pt',
version=version,
Expand All @@ -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="""
Expand Down
129 changes: 65 additions & 64 deletions src/five/pt/expressions.py
Expand Up @@ -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
Expand All @@ -34,10 +42,49 @@
_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, \
Expand All @@ -54,35 +101,6 @@ def static(obj):
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'

Expand Down Expand Up @@ -110,14 +128,17 @@ def traverse(cls, base, request, path_items):

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

Expand All @@ -127,7 +148,9 @@ class TrustedBoboAwareZopeTraverse(BoboAwareZopeTraverse):

__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:
Expand Down Expand Up @@ -162,28 +185,6 @@ class ExistsExpr(expressions.ExistsExpr):
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,
Expand Down

0 comments on commit 5fe7f20

Please sign in to comment.