Merge lp:~wallyworld/zope.pagetemplate/fix-isinstance into lp:zope.pagetemplate

Proposed by Ian Booth
Status: Needs review
Proposed branch: lp:~wallyworld/zope.pagetemplate/fix-isinstance
Merge into: lp:zope.pagetemplate
Diff against target: 91 lines (+45/-4)
2 files modified
src/zope/pagetemplate/engine.py (+4/-4)
src/zope/pagetemplate/tests/test_engine.py (+41/-0)
To merge this branch: bzr merge lp:~wallyworld/zope.pagetemplate/fix-isinstance
Reviewer Review Type Date Requested Status
Tres Seaver Approve
Review via email: mp+38499@code.launchpad.net

Description of the change

I have made a small improvement to the short circuit in the traversal logic if the object subclasses dict.

The code in engine.py used to say:

if getattr(object, '__class__', None) == dict:

It has been changed to:

if isinstance(object, dict):

The reason for the change is that I have made some optimisations to Launchpad menu rendering and now there's instances of MenuLinksDict(dict) classes instead of vanilla dicts. These new instances extend dict and so the original check in engine.py failed. My change arguably is the better way to do the check and it makes the short circuit work again for Launchpad menus :-)

To post a comment you must log in.
Revision history for this message
Tres Seaver (tseaver) wrote :

Overall, the patch looks fine, but it needs a test showing that the
subclassing bit (the part you care about) works.

review: Needs Fixing
59. By Ian Booth

Add unit tests

Revision history for this message
Ian Booth (wallyworld) wrote :

Hi Tres

Thanks for the review. I've added a new unit test to test_engine.py
which verifies that the traversal works as expected. Let me know if
there's any issues.

On 26/10/10 11:22, Tres Seaver wrote:
> Review: Needs Fixing
> Overall, the patch looks fine, but it needs a test showing that the
> subclassing bit (the part you care about) works.

Revision history for this message
Tres Seaver (tseaver) wrote :

Thanks for adding the tests -- looks good.

review: Approve
Revision history for this message
Colin Watson (cjwatson) wrote :

Since this had apparently fallen off the radar and in any case failed tests when rebased, I resubmitted this in a modified form as https://github.com/zopefoundation/zope.pagetemplate/pull/3.

Unmerged revisions

59. By Ian Booth

Add unit tests

58. By Ian Booth

Improve isinstance call

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/zope/pagetemplate/engine.py'
2--- src/zope/pagetemplate/engine.py 2010-06-03 16:09:29 +0000
3+++ src/zope/pagetemplate/engine.py 2010-10-26 04:26:42 +0000
4@@ -57,9 +57,9 @@
5
6 while path_items:
7 name = path_items.pop()
8-
9+
10 # special-case dicts for performance reasons
11- if getattr(object, '__class__', None) == dict:
12+ if isinstance(object, dict):
13 object = object[name]
14 else:
15 object = traversePathElement(object, name, path_items,
16@@ -141,10 +141,10 @@
17 """evaluateMacro gets security-proxied macro programs when this
18 is run with the zopeTraverser, and in other untrusted
19 situations. This will cause evaluation to fail in
20- zope.tal.talinterpreter, which knows nothing of security proxies.
21+ zope.tal.talinterpreter, which knows nothing of security proxies.
22 Therefore, this method removes any proxy from the evaluated
23 expression.
24-
25+
26 >>> output = [('version', 'xxx'), ('mode', 'html'), ('other', 'things')]
27 >>> def expression(context):
28 ... return ProxyFactory(output)
29
30=== modified file 'src/zope/pagetemplate/tests/test_engine.py'
31--- src/zope/pagetemplate/tests/test_engine.py 2010-06-03 16:09:29 +0000
32+++ src/zope/pagetemplate/tests/test_engine.py 2010-10-26 04:26:42 +0000
33@@ -14,6 +14,7 @@
34 """Doc tests for the pagetemplate's 'engine' module
35 """
36 import unittest
37+from zope.traversing.interfaces import ITraversable
38
39 class DummyNamespace(object):
40
41@@ -79,12 +80,52 @@
42 self.assertRaises(NameError, expr, DummyContext())
43
44
45+class ZopeTraverserTests(unittest.TestCase):
46+
47+ class TraverserDict(dict):
48+ def __init__(self):
49+ self.item_requested = None
50+
51+ def __getitem__(self, item):
52+ self.item_requested = item
53+ return dict.__getitem__(self, item)
54+
55+ class DummyTraverser():
56+ implements = ITraversable
57+
58+ def __init__(self, obj):
59+ self.traversed = obj
60+
61+ def traverse(self, name, furtherPath):
62+ return name+self.traversed
63+
64+ def test_dict_shortcut(self):
65+ from zope.pagetemplate.engine import ZopeTraverser
66+ traverser = ZopeTraverser()
67+
68+ obj = ZopeTraverserTests.TraverserDict()
69+ obj['foo'] = 'bar'
70+ result = traverser(obj, ['foo'], {})
71+ self.assertEqual(obj.item_requested, 'foo')
72+ self.assertEqual('bar', result)
73+
74+ def test_nondict_traversal(self):
75+ from zope.component import provideAdapter
76+ from zope.pagetemplate.engine import ZopeTraverser
77+ traverser = ZopeTraverser()
78+ provideAdapter(
79+ ZopeTraverserTests.DummyTraverser, (None,), ITraversable, name='')
80+
81+ result = traverser('bar', ['foo'], {})
82+ self.assertEqual('foobar', result)
83+
84 def test_suite():
85 from doctest import DocTestSuite
86 suite = unittest.TestSuite()
87 suite.addTest(DocTestSuite('zope.pagetemplate.engine'))
88 suite.addTest(unittest.makeSuite(EngineTests))
89 suite.addTest(unittest.makeSuite(ZopePythonExprTests))
90+ suite.addTest(unittest.makeSuite(ZopeTraverserTests))
91 return suite
92
93

Subscribers

People subscribed via source and target branches