[Checkins] SVN: z3c.pt/trunk/ Fixed bug where a getattr-expression (the dot operator) would result in two or three accesses.

Malthe Borch mborch at gmail.com
Fri Feb 22 18:46:15 EST 2008


Log message for revision 84151:
  Fixed bug where a getattr-expression (the dot operator) would result in two or three accesses.

Changed:
  U   z3c.pt/trunk/setup.py
  U   z3c.pt/trunk/z3c/pt/BENCHMARKS.txt
  U   z3c.pt/trunk/z3c/pt/codegen.py
  U   z3c.pt/trunk/z3c/pt/codegen.txt
  U   z3c.pt/trunk/z3c/pt/pagetemplate.py

-=-
Modified: z3c.pt/trunk/setup.py
===================================================================
--- z3c.pt/trunk/setup.py	2008-02-22 22:48:17 UTC (rev 84150)
+++ z3c.pt/trunk/setup.py	2008-02-22 23:46:13 UTC (rev 84151)
@@ -1,6 +1,6 @@
 from setuptools import setup, find_packages
 
-version = '0.4'
+version = '0.4.1'
 
 setup(name='z3c.pt',
       version=version,

Modified: z3c.pt/trunk/z3c/pt/BENCHMARKS.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/BENCHMARKS.txt	2008-02-22 22:48:17 UTC (rev 84150)
+++ z3c.pt/trunk/z3c/pt/BENCHMARKS.txt	2008-02-22 23:46:13 UTC (rev 84151)
@@ -16,8 +16,7 @@
 50x factor in the 'Hello World' benchmark versus a pure python
 implementation.
 
-Certainly a specialized implementation will always be faster. But
-there's still some room for improvement.
+Certainly a specialized implementation will always be faster.
 
 Benchmark source code
 ---------------------
@@ -67,7 +66,7 @@
   ...   </tr>
   ... </table>""")
 
-  >>> for i in range(40): a = template(table=table)
+  >>> # for i in range(40): a = template(table=table)
   
   >>> template = z3PageTemplate()
   >>> template.pt_edit("""\

Modified: z3c.pt/trunk/z3c/pt/codegen.py
===================================================================
--- z3c.pt/trunk/z3c/pt/codegen.py	2008-02-22 22:48:17 UTC (rev 84150)
+++ z3c.pt/trunk/z3c/pt/codegen.py	2008-02-22 23:46:13 UTC (rev 84151)
@@ -7,6 +7,33 @@
 
 CONSTANTS = frozenset(['False', 'True', 'None', 'NotImplemented', 'Ellipsis'])
 
+UNDEFINED = object()
+
+class Lookup(object):
+    """Abstract base class for variable lookup implementations."""
+
+    def globals(cls):
+        """Construct the globals dictionary to use as the execution context for
+        the expression or suite.
+        """
+        return {
+            '_lookup_attr': cls.lookup_attr,
+        }
+
+    globals = classmethod(globals)
+
+    @classmethod
+    def lookup_attr(cls, obj, key):
+        __traceback_hide__ = True
+        val = getattr(obj, key, UNDEFINED)
+        if val is UNDEFINED:
+            try:
+                val = obj[key]
+            except (KeyError, TypeError):
+                raise AttributeError(key)
+
+        return val
+
 class TemplateASTTransformer(ASTTransformer):
     def __init__(self):
         self.locals = [CONSTANTS]
@@ -22,20 +49,12 @@
         if hasattr(node.expr, 'name') and node.expr.name.startswith('_'):
             return ast.Getattr(node.expr, node.attrname)
 
-        expr = self.visit(node.expr)
-        name = ast.Const(node.attrname)
-
-        # hasattr(obj, key) and getattr(obj, key) or not
-        # hasattr(obj, key) and obj[key]
-        return ast.Or([ast.And(
-            [ast.CallFunc(ast.Name('hasattr'), [expr, name], None, None),
-             ast.CallFunc(ast.Name('getattr'), [expr, name], None, None)]),
-                    ast.And([
-            ast.Not(ast.CallFunc(ast.Name('hasattr'), [expr, name], None, None)),
-            ast.Subscript(expr, 'OP_APPLY', [name])])])
+        return ast.CallFunc(ast.Name('_lookup_attr'), [
+            self.visit(node.expr), ast.Const(node.attrname)
+            ])
     
 class Suite(object):
-    __slots__ = ['code']
+    __slots__ = ['code', '_globals']
 
     xform = TemplateASTTransformer
     mode = 'exec'
@@ -54,6 +73,7 @@
         gen = ModuleCodeGenerator(tree)
         gen.optimized = True
 
+        self._globals = Lookup.globals()
         self.code = gen.getCode()
         
     def __hash__(self):

Modified: z3c.pt/trunk/z3c/pt/codegen.txt
===================================================================
--- z3c.pt/trunk/z3c/pt/codegen.txt	2008-02-22 22:48:17 UTC (rev 84150)
+++ z3c.pt/trunk/z3c/pt/codegen.txt	2008-02-22 23:46:13 UTC (rev 84151)
@@ -14,7 +14,7 @@
   >>> suite = Suite("""\
   ... print 'Hello World!'
   ... """)
-  >>> exec suite.code
+  >>> exec suite.code in suite._globals
   Hello World!
 
 AST transformations
@@ -28,4 +28,4 @@
   ... a = {'b': 1}
   ... assert a['b'] == a.b
   ... """)
-  >>> exec suite.code
+  >>> exec suite.code in suite._globals

Modified: z3c.pt/trunk/z3c/pt/pagetemplate.py
===================================================================
--- z3c.pt/trunk/z3c/pt/pagetemplate.py	2008-02-22 22:48:17 UTC (rev 84150)
+++ z3c.pt/trunk/z3c/pt/pagetemplate.py	2008-02-22 23:46:13 UTC (rev 84151)
@@ -14,8 +14,7 @@
         source, _globals = translation.translate(self.body, params)
         suite = codegen.Suite(source)
 
-        self.source = source
-
+        _globals.update(suite._globals)
         _locals = {}
 
         exec suite.code in _globals, _locals



More information about the Checkins mailing list