Merge pull request #2 from pjenvey/master
simplify
diff --git a/CHANGES b/CHANGES
index 4b04cb7..d43cbd3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,10 @@
0.9.0
+- [bug] The Context.locals_() method becomes a private underscored
+ method, as this method has a specific internal use. The purpose
+ of Context.kwargs has been clarified, in that it only delivers
+ top level keyword arguments originally passed to template.render().
+ [ticket:219]
+
- [bug] Fixed the babel plugin to properly interpret ${} sections
inside of a "call" tag, i.e. <%self:some_tag attr="${_('foo')}"/>.
Code that's subject to babel escapes in here needs to be
diff --git a/doc/build/namespaces.rst b/doc/build/namespaces.rst
index 078b15a..1453b80 100644
--- a/doc/build/namespaces.rst
+++ b/doc/build/namespaces.rst
@@ -245,9 +245,9 @@
${self.body(5, y=10, someval=15, delta=7)}
-The :class:`.Context` object also supplies a :attr:`~.Context.kwargs` accessor, for
-cases when you'd like to pass along whatever is in the context to
-a ``body()`` callable:
+The :class:`.Context` object also supplies a :attr:`~.Context.kwargs`
+accessor, for cases when you'd like to pass along the top level context
+arguments to a ``body()`` callable:
.. sourcecode:: mako
diff --git a/mako/codegen.py b/mako/codegen.py
index 0e377ec..971538c 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -14,7 +14,7 @@
from mako import compat
-MAGIC_NUMBER = 8
+MAGIC_NUMBER = 9
# names which are hardwired into the
# template and are not accessed via the
@@ -548,7 +548,7 @@
if not self.in_def and (
len(self.identifiers.locally_assigned) > 0 or
len(self.identifiers.argument_declared) > 0):
- nameargs.insert(0, 'context.locals_(__M_locals)')
+ nameargs.insert(0, 'context._locals(__M_locals)')
else:
nameargs.insert(0, 'context')
self.printer.writeline("def %s(%s):" % (funcname, ",".join(namedecls)))
diff --git a/mako/runtime.py b/mako/runtime.py
index 5c8cfe7..f94c109 100644
--- a/mako/runtime.py
+++ b/mako/runtime.py
@@ -58,8 +58,22 @@
@property
def kwargs(self):
- """Return the dictionary of keyword arguments associated with this
- :class:`.Context`.
+ """Return the dictionary of top level keyword arguments associated
+ with this :class:`.Context`.
+
+ This dictionary only includes the top-level arguments passed to
+ :meth:`.Template.render`. It does not include names produced within
+ the template execution such as local variable names or special names
+ such as ``self``, ``next``, etc.
+
+ The purpose of this dictionary is primarily for the case that
+ a :class:`.Template` accepts arguments via its ``<%page>`` tag,
+ which are normally expected to be passed via :meth:`.Template.render`,
+ except the template is being called in an inheritance context,
+ using the ``body()`` method. :attr:`.Context.kwargs` can then be
+ used to propagate these arguments to the inheriting template::
+
+ ${next.body(**context.kwargs)}
"""
return self._kwargs.copy()
@@ -144,11 +158,18 @@
c.caller_stack = self.caller_stack
return c
- def locals_(self, d):
+ def _locals(self, d):
"""Create a new :class:`.Context` with a copy of this
- :class:`.Context`'s current state, updated with the given dictionary."""
+ :class:`.Context`'s current state,
+ updated with the given dictionary.
- if len(d) == 0:
+ The :attr:`.Context.kwargs` collection remains
+ unaffected.
+
+
+ """
+
+ if not d:
return self
c = self._copy()
c._data.update(d)
@@ -173,19 +194,22 @@
return self.__bool__()
def __bool__(self):
- return self._get_caller() and True or False
+ return len(self) and self._get_caller() and True or False
def _get_caller(self):
# this method can be removed once
# codegen MAGIC_NUMBER moves past 7
return self[-1]
+
def __getattr__(self, key):
return getattr(self._get_caller(), key)
+
def _push_frame(self):
frame = self.nextcaller or None
self.append(frame)
self.nextcaller = None
return frame
+
def _pop_frame(self):
self.nextcaller = self.pop()
@@ -721,10 +745,10 @@
ih = self_ns
while ih.inherits is not None:
ih = ih.inherits
- lclcontext = context.locals_({'next':ih})
+ lclcontext = context._locals({'next': ih})
ih.inherits = TemplateNamespace("self:%s" % template.uri,
lclcontext,
- template = template,
+ template=template,
populate_self=False)
context._data['parent'] = lclcontext._data['local'] = ih.inherits
callable_ = getattr(template.module, '_mako_inherit', None)
diff --git a/test/test_runtime.py b/test/test_runtime.py
new file mode 100644
index 0000000..af7dbee
--- /dev/null
+++ b/test/test_runtime.py
@@ -0,0 +1,21 @@
+"""Assorted runtime unit tests
+"""
+from mako import runtime
+import unittest
+from . import eq_
+
+class ContextTest(unittest.TestCase):
+ def test_locals_kwargs(self):
+ c = runtime.Context(None, foo='bar')
+ eq_(c.kwargs, {'foo': 'bar'})
+
+ d = c._locals({'zig': 'zag'})
+
+ # kwargs is the original args sent to the Context,
+ # it's intentionally kept separate from _data
+ eq_(c.kwargs, {'foo': 'bar'})
+ eq_(d.kwargs, {'foo': 'bar'})
+
+ eq_(d._data['zig'], 'zag')
+
+