diff options
author | Colin Watson <cjwatson@canonical.com> | 2015-01-20 14:35:39 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@canonical.com> | 2015-01-20 14:35:39 +0000 |
commit | 0047f1d611d2377d908f89445ba5d4dfa72d86b0 (patch) | |
tree | 2287b3f5684af4f8a93afd449e4c17d373a7fe59 /src | |
parent | 25878709d9fe3f50135005703dcfaccda23b9eca (diff) | |
download | zope-pagetemplate-0047f1d611d2377d908f89445ba5d4dfa72d86b0.tar.gz |
Allow short-circuit traversal for non-proxied dict subclasses
This change is based on
https://code.launchpad.net/~wallyworld/zope.pagetemplate/fix-isinstance/+merge/38499
by Ian Booth.
The original approach in that branch broke tests, because they rely on
subclassing dict with an implementer of ITraversable. Rather than changing
this, it seems safer to only extend the dict special-case to non-proxied
subclasses.
Diffstat (limited to 'src')
-rw-r--r-- | src/zope/pagetemplate/engine.py | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/src/zope/pagetemplate/engine.py b/src/zope/pagetemplate/engine.py index 99634fa..df307e7 100644 --- a/src/zope/pagetemplate/engine.py +++ b/src/zope/pagetemplate/engine.py @@ -22,6 +22,7 @@ import sys from zope import component from zope.interface import implementer from zope.component.interfaces import ComponentLookupError +from zope.proxy import isProxy from zope.traversing.interfaces import IPathAdapter, ITraversable from zope.traversing.interfaces import TraversalError from zope.traversing.adapters import traversePathElement @@ -66,6 +67,8 @@ class ZopeTraverser(object): # special-case dicts for performance reasons if getattr(object, '__class__', None) == dict: object = object[name] + elif isinstance(object, dict) and not isProxy(object): + object = object[name] else: object = traversePathElement(object, name, path_items, request=request) @@ -386,6 +389,25 @@ class ZopeEngine(ZopeBaseEngine): ... KeyError: 'keys' + This special-casing also applies to non-proxied dict subclasses: + + >>> class TraverserDict(dict): + ... def __init__(self): + ... self.item_requested = None + ... def __getitem__(self, item): + ... self.item_requested = item + ... return dict.__getitem__(self, item) + + >>> d = engine.getBaseNames() + >>> foo = TraverserDict() + >>> d['foo'] = foo + >>> foo['bar'] = 'baz' + >>> context = engine.getContext(d) + >>> context.evaluate('foo/bar') + 'baz' + >>> foo.item_requested + 'bar' + >>> tearDown() """ |