changeset 682:0653f6c1ffdf trunk

Assigning to a variable named `data` in a Python code block no longer breaks context lookup. We now use the name `__data__` for internal data, hoping that that name is not as commonly used in templates.
author cmlenz
date Wed, 06 Feb 2008 12:18:02 +0000
parents 3e7cd32c9411
children 0fcb1c0d7c20
files ChangeLog genshi/template/eval.py genshi/template/tests/eval.py
diffstat 3 files changed, 23 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -44,6 +44,8 @@
    so that it is still possible to use the Genshi `escape` function even with
    text templates. The old behavior is available via the `strip_markup` option
    of the serializer (ticket #146).
+ * Assigning to a variable named `data` in a Python code block no longer
+   breaks context lookup.
 
 
 Version 0.4.4
--- a/genshi/template/eval.py
+++ b/genshi/template/eval.py
@@ -140,8 +140,8 @@
         """
         __traceback_hide__ = 'before_and_this'
         _globals = self._globals()
-        _globals['data'] = data
-        return eval(self.code, _globals, {'data': data})
+        _globals['__data__'] = data
+        return eval(self.code, _globals, {'__data__': data})
 
 
 class Suite(Code):
@@ -162,7 +162,7 @@
         """
         __traceback_hide__ = 'before_and_this'
         _globals = self._globals()
-        _globals['data'] = data
+        _globals['__data__'] = data
         exec self.code in _globals, data
 
 
@@ -678,11 +678,11 @@
         if isinstance(node.node, ast.Name) \
                 and node.node.name not in flatten(self.locals):
             name = node.node.name
-            node.node = ast.Subscript(ast.Name('data'), 'OP_APPLY',
+            node.node = ast.Subscript(ast.Name('__data__'), 'OP_APPLY',
                                       [ast.Const(name)])
             node.expr = self.visit(node.expr)
             return ast.If([
-                (ast.Compare(ast.Const(name), [('in', ast.Name('data'))]),
+                (ast.Compare(ast.Const(name), [('in', ast.Name('__data__'))]),
                  ast.Stmt([node]))],
                 ast.Stmt([ast.Raise(ast.CallFunc(ast.Name('UndefinedError'),
                                                  [ast.Const(name)]),
@@ -741,7 +741,7 @@
         # generator expression, leave it alone
         if node.name not in flatten(self.locals):
             # Otherwise, translate the name ref into a context lookup
-            func_args = [ast.Name('data'), ast.Const(node.name)]
+            func_args = [ast.Name('__data__'), ast.Const(node.name)]
             node = ast.CallFunc(ast.Name('_lookup_name'), func_args)
         return node
 
@@ -753,12 +753,12 @@
 
     def visitGetattr(self, node):
         return ast.CallFunc(ast.Name('_lookup_attr'), [
-            ast.Name('data'), self.visit(node.expr),
+            ast.Name('__data__'), self.visit(node.expr),
             ast.Const(node.attrname)
         ])
 
     def visitSubscript(self, node):
         return ast.CallFunc(ast.Name('_lookup_item'), [
-            ast.Name('data'), self.visit(node.expr),
+            ast.Name('__data__'), self.visit(node.expr),
             ast.Tuple([self.visit(sub) for sub in node.subs])
         ])
--- a/genshi/template/tests/eval.py
+++ b/genshi/template/tests/eval.py
@@ -438,6 +438,19 @@
 
 class SuiteTestCase(unittest.TestCase):
 
+    def test_internal_shadowing(self):
+        # The context itself is stored in the global execution scope of a suite
+        # It used to get stored under the name 'data', which meant the
+        # following test would fail, as the user defined 'data' variable
+        # shadowed the Genshi one. We now use the name '__data__' to avoid
+        # conflicts
+        suite = Suite("""data = []
+bar = foo
+""")
+        data = {'foo': 42}
+        suite.execute(data)
+        self.assertEqual(42, data['bar'])
+
     def test_assign(self):
         suite = Suite("foo = 42")
         data = {}
Copyright (C) 2012-2017 Edgewall Software