[Zope3-checkins] SVN: Zope3/trunk/ Merge from 3.3 branch:

Philipp von Weitershausen philikon at philikon.de
Thu May 25 15:28:48 EDT 2006


Log message for revision 68283:
  Merge from 3.3 branch:
  
  ------------------------------------------------------------------------
  r68278 | philikon | 2006-05-25 19:49:12 +0200 (Thu, 25 May 2006) | 2 lines
  
  Do not blindly call exception classes or arbitrary objects inserted here.
  
  ------------------------------------------------------------------------
  r68279 | philikon | 2006-05-25 19:50:09 +0200 (Thu, 25 May 2006) | 3 lines
  
  Fix http://www.zope.org/Collectors/Zope3-dev/635:
    TALES PathExpr doesn't calls old style classes
  
  ------------------------------------------------------------------------
  r68280 | philikon | 2006-05-25 19:51:17 +0200 (Thu, 25 May 2006) | 2 lines
  
  Note recent change
  
  ------------------------------------------------------------------------
  r68281 | philikon | 2006-05-25 20:08:02 +0200 (Thu, 25 May 2006) | 5 lines
  
  Fix http://www.zope.org/Collectors/Zope3-dev/638:
    TALES PathExpr calls result of alternate subexpression
  
  This corresponds to issue 538 in Zope 2 and r22855 in the Zope 2 trunk.
  
  ------------------------------------------------------------------------
  r68282 | philikon | 2006-05-25 20:59:25 +0200 (Thu, 25 May 2006) | 3 lines
  
  Fix http://www.zope.org/Collectors/Zope3-dev/636:
    Default ITraverser can't traverse old style classes
  
  

Changed:
  U   Zope3/trunk/doc/CHANGES.txt
  U   Zope3/trunk/src/zope/app/debugskin/error_debug.pt
  U   Zope3/trunk/src/zope/tales/expressions.py
  U   Zope3/trunk/src/zope/tales/tests/test_expressions.py
  U   Zope3/trunk/src/zope/traversing/adapters.py
  U   Zope3/trunk/src/zope/traversing/tests/test_traverser.py

-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt	2006-05-25 18:59:25 UTC (rev 68282)
+++ Zope3/trunk/doc/CHANGES.txt	2006-05-25 19:28:47 UTC (rev 68283)
@@ -16,6 +16,14 @@
 
     Bug fixes
 
+      - Fixed issue 636: Default ITraverser can't traverse old style
+        classes
+
+      - Fixed issue 638: TALES PathExpr calls result of alternate
+        subexpression
+
+      - Fixed issue 635: TALES PathExpr doesn't call old style classes
+
       - Fixed issue 543: add 'decimal'-package to
         zope/app/security/globalmodules.zcml
 

Modified: Zope3/trunk/src/zope/app/debugskin/error_debug.pt
===================================================================
--- Zope3/trunk/src/zope/app/debugskin/error_debug.pt	2006-05-25 18:59:25 UTC (rev 68282)
+++ Zope3/trunk/src/zope/app/debugskin/error_debug.pt	2006-05-25 19:28:47 UTC (rev 68283)
@@ -5,12 +5,12 @@
 
   <h3 i18n:translate="">
     Error type: 
-    <tal:span tal:replace="view/error_type" i18n:name="error_type"/>
+    <tal:span tal:replace="nocall:view/error_type" i18n:name="error_type"/>
   </h3>
 
   <h5 i18n:translate="">
     Error object: 
-    <tal:span tal:replace="view/error_object" i18n:name="error_object"/>
+    <tal:span tal:replace="nocall:view/error_object" i18n:name="error_object"/>
   </h5>
 
   <pre class="traceback" style="font-size:small;">
@@ -21,4 +21,3 @@
 </div>
 </body>
 </html>
-

Modified: Zope3/trunk/src/zope/tales/expressions.py
===================================================================
--- Zope3/trunk/src/zope/tales/expressions.py	2006-05-25 18:59:25 UTC (rev 68282)
+++ Zope3/trunk/src/zope/tales/expressions.py	2006-05-25 19:28:47 UTC (rev 68283)
@@ -15,7 +15,7 @@
 
 $Id$
 """
-import re
+import re, types
 
 from zope.interface import implements
 from zope.tales.tales import _valid_name, _parse_expr, NAME_RE, Undefined
@@ -139,7 +139,6 @@
         return ob
 
 
-
 class PathExpr(object):
     """One or more subpath expressions, separated by '|'."""
     implements(ITALESExpression)
@@ -156,6 +155,7 @@
     def __init__(self, name, expr, engine, traverser=simpleTraverse):
         self._s = expr
         self._name = name
+        self._hybrid = False
         paths = expr.split('|')
         self._subexprs = []
         add = self._subexprs.append
@@ -165,6 +165,7 @@
                 # This part is the start of another expression type,
                 # so glue it back together and compile it.
                 add(engine.compile('|'.join(paths[i:]).lstrip()))
+                self._hybrid = True
                 break
             add(SubPathExpr(path, traverser, engine)._eval)
 
@@ -188,14 +189,25 @@
             else:
                 break
         else:
-            # On the last subexpression allow exceptions through.
+            # On the last subexpression allow exceptions through, and
+            # don't autocall if the expression was not a subpath.
             ob = self._subexprs[-1](econtext)
+            if self._hybrid:
+                return ob
 
         if self._name == 'nocall':
             return ob
 
-        # Call the object if it is callable.
-        if hasattr(ob, '__call__'):
+        # Call the object if it is callable.  Note that checking for
+        # callable() isn't safe because the object might be security
+        # proxied (and security proxies report themselves callable, no
+        # matter what the underlying object is).  We therefore check
+        # for the __call__ attribute, but not with hasattr as that
+        # eats babies, err, exceptions.  In addition to that, we
+        # support calling old style classes which don't have a
+        # __call__.
+        if (getattr(ob, '__call__', _marker) is not _marker
+            or isinstance(ob, types.ClassType)):
             return ob()
         return ob
 

Modified: Zope3/trunk/src/zope/tales/tests/test_expressions.py
===================================================================
--- Zope3/trunk/src/zope/tales/tests/test_expressions.py	2006-05-25 18:59:25 UTC (rev 68282)
+++ Zope3/trunk/src/zope/tales/tests/test_expressions.py	2006-05-25 19:28:47 UTC (rev 68283)
@@ -114,6 +114,13 @@
                              'Dynamic name specified in first subpath element')
         else:
             self.fail('Engine accepted first subpath element as dynamic')
+
+    def testOldStyleClassIsCalled(self):
+        class AnOldStyleClass:
+            pass
+        self.context.vars['oldstyleclass'] = AnOldStyleClass
+        expr = self.engine.compile('oldstyleclass')
+        self.assert_(isinstance(expr(self.context), AnOldStyleClass))
             
     def testString(self):
         expr = self.engine.compile('string:Fred')
@@ -135,6 +142,11 @@
         context=self.context
         self.assertEqual(expr(context), 4)
 
+    def testPythonCallableIsntCalled(self):
+        self.context.vars['acallable'] = lambda: 23
+        expr = self.engine.compile('python: acallable')
+        self.assertEqual(expr(self.context), self.context.vars['acallable'])
+
     def testPythonNewline(self):
         expr = self.engine.compile('python: 2 \n+\n 2\n')
         context=self.context
@@ -149,6 +161,20 @@
         self.assertRaises(self.engine.getCompilerError(),
                           self.engine.compile, 'python: splat.0')
 
+    def testHybridPathExpressions(self):
+        def eval(expr):
+            e = self.engine.compile(expr)
+            return e(self.context)
+        self.context.vars['one'] = 1
+        self.context.vars['acallable'] = lambda: 23
+
+        self.assertEqual(eval('foo | python:1+1'), 2)
+        self.assertEqual(eval('foo | python:acallable'),
+                         self.context.vars['acallable'])
+        self.assertEqual(eval('foo | string:x'), 'x')
+        self.assertEqual(eval('foo | string:$one'), '1')
+        self.assert_(eval('foo | exists:x'))
+
     def testEmptyPathSegmentRaisesCompilerError(self):
         CompilerError = self.engine.getCompilerError()
         def check(expr):

Modified: Zope3/trunk/src/zope/traversing/adapters.py
===================================================================
--- Zope3/trunk/src/zope/traversing/adapters.py	2006-05-25 18:59:25 UTC (rev 68282)
+++ Zope3/trunk/src/zope/traversing/adapters.py	2006-05-25 19:28:47 UTC (rev 68283)
@@ -158,7 +158,8 @@
         nm = name
 
     if traversable is None:
-        if obj.__class__ == dict:
+        # not all objects have __class__, for example old style classes
+        if getattr(obj, '__class__', None) == dict:
             # Special-case dicts
             return obj[name]
 

Modified: Zope3/trunk/src/zope/traversing/tests/test_traverser.py
===================================================================
--- Zope3/trunk/src/zope/traversing/tests/test_traverser.py	2006-05-25 18:59:25 UTC (rev 68282)
+++ Zope3/trunk/src/zope/traversing/tests/test_traverser.py	2006-05-25 19:28:47 UTC (rev 68283)
@@ -137,6 +137,15 @@
     def testNotFoundNoDefault(self):
         self.assertRaises(TraversalError, self.tr.traverse, 'foo')
 
+    def testTraverseOldStyleClass(self):
+        class AnOldStyleClass:
+            x = object()
+        container = {}
+        container['theclass'] = AnOldStyleClass
+
+        tr = Traverser(container)
+        self.assert_(tr.traverse('theclass/x') is AnOldStyleClass.x)
+
 class RestrictedTraverseTests(PlacefulSetup, unittest.TestCase):
     _oldPolicy = None
     _deniedNames = ()



More information about the Zope3-Checkins mailing list