diff --git a/CHANGES.rst b/CHANGES.rst index e7ec251..bbf9168 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,10 @@ 5.2.0 (unreleased) ================== +- ``tales.Context.getValue`` now returns the innermost (not outermost) + value for the given variable. Fixes + `#19 `_. + - Add support for Python 3.9, 3.10. - Fix error message raised if the first element of a path expression is not diff --git a/src/zope/tales/tales.py b/src/zope/tales/tales.py index d5ca006..4f9a08a 100644 --- a/src/zope/tales/tales.py +++ b/src/zope/tales/tales.py @@ -744,12 +744,16 @@ def setGlobal(self, name, value): vars[name] = value def getValue(self, name, default=None): - value = default - for vars in self._vars_stack: - value = vars.get(name, default) - if value is not default: - break - return value + """return the current value of variable *name* or *default*.""" + # ``beginScope`` puts a copy of all variables into ``vars`` + # and pushes it onto ``_vars_stack``, + # ``endScope`` pops the last element of ``vars_stack`` into ``vars``, + # ``setGlobal`` updates all variable bindings in ``_vars_stack`` + # (and thereby, implicitly, ``vars``). + # Consequently, the current value of a variable can + # always be found in ``vars`` + # (no need to iterate over ``_vars_stack``). + return self.vars.get(name, default) def setRepeat(self, name, expr): expr = self.evaluate(expr) diff --git a/src/zope/tales/tests/test_tales.py b/src/zope/tales/tests/test_tales.py index 03a1fe5..508a174 100644 --- a/src/zope/tales/tests/test_tales.py +++ b/src/zope/tales/tests/test_tales.py @@ -134,6 +134,7 @@ def testVariables(self): c = ctxt.vars self.assertEqual(c['v1'], 1, 'Variable "v1"') + self.assertEqual(ctxt.getValue('v1'), 1, 'Variable "v1"') ctxt.beginScope() ctxt.setLocal('v1', 3) @@ -141,14 +142,19 @@ def testVariables(self): c = ctxt.vars self.assertEqual(c['v1'], 3, 'Inner scope') + self.assertEqual(ctxt.getValue('v1'), 3, 'Inner scope') self.assertEqual(c['v2'], 2, 'Outer scope') + self.assertEqual(ctxt.getValue('v2'), 2, 'Outer scope') self.assertEqual(c['g'], 1, 'Global') + self.assertEqual(ctxt.getValue('g'), 1, 'Global') ctxt.endScope() c = ctxt.vars self.assertEqual(c['v1'], 1, "Uncovered local") + self.assertEqual(ctxt.getValue('v1'), 1, "Uncovered local") self.assertEqual(c['g'], 1, "Global from inner scope") + self.assertEqual(ctxt.getValue('g'), 1, "Global from inner scope") ctxt.endScope() @@ -220,7 +226,7 @@ def test_getValue_nested(self): self.context.vars['it'] = 1 self.context.beginScope() self.context.vars['it'] = 2 - self.assertEqual(self.context.getValue('it'), 1) + self.assertEqual(self.context.getValue('it'), 2) def test_evaluate_boolean(self): # Make sure it always returns a regular bool, no matter