Made the new template.Context.flatten() method a public API.

That method was introduced in 9db4271bd1.

Refs #21765.
This commit is contained in:
Marek Wywiał 2014-02-16 14:50:27 +01:00 committed by Baptiste Mispelon
parent 57ba5bf97b
commit 8274fa60f8
4 changed files with 66 additions and 7 deletions

View File

@ -97,6 +97,15 @@ class BaseContext(object):
new_context._reset_dicts(values)
return new_context
def flatten(self):
"""
Returns self.dicts as one dictionary
"""
flat = {}
for d in self.dicts:
flat.update(d)
return flat
def __eq__(self, other):
"""
Compares two contexts by comparing theirs 'dicts' attributes.
@ -104,13 +113,7 @@ class BaseContext(object):
if isinstance(other, BaseContext):
# because dictionaries can be put in different order
# we have to flatten them like in templates
def flatten(dicts):
flat = {}
for d in dicts:
flat.update(d)
return flat
return flatten(self.dicts) == flatten(other.dicts)
return self.flatten() == other.flatten()
# if it's not comparable return false
return False

View File

@ -368,6 +368,43 @@ the stack instead of an empty one.
Using a ``Context`` as a stack comes in handy in some custom template tags, as
you'll see below.
.. method:: Context.flatten()
.. versionadded:: 1.7
Using ``flatten()`` method you can get whole ``Context`` stack as one dictionary
including builtin variables.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'bar': 'second level'})
{'bar': 'second level'}
>>> c.flatten()
{'True': True, 'None': None, 'foo': 'first level', 'False': False, 'bar': 'second level'}
A ``flatten()`` method is also internally used to make ``Context`` objects comparable.
>>> c1 = Context()
>>> c1['foo'] = 'first level'
>>> c1['bar'] = 'second level'
>>> c2 = Context()
>>> c2.update({'bar': 'second level', 'foo': 'first level'})
{'foo': 'first level', 'bar': 'second level'}
>>> c1 == c2
True
Result from ``flatten()`` can be useful in unit tests to compare ``Context``
against ``dict``::
class ContextTest(unittest.TestCase):
def test_against_dictionary(self):
c1 = Context()
c1['update'] = 'value'
self.assertEqual(c1.flatten(), {
'True': True, 'None': None, 'False': False,
'update': 'value'})
.. _subclassing-context-requestcontext:
Subclassing Context: RequestContext

View File

@ -636,6 +636,14 @@ Templates
parameters that are passed to the ``dict`` constructor used to build the new
context level.
* The new :meth:`Context.flatten() <django.template.Context.flatten>` method
returns a ``Context``'s stack as one flat dictionary.
* ``Context`` objects can now be compared for equality (internally, this
uses :meth:`Context.flatten() <django.template.Context.flatten>` so the
internal structure of each ``Context``'s stack doesn't matter as long as their
flattened version is identical).
* The :ttag:`widthratio` template tag now accepts an "as" parameter to capture
the result in a variable.

View File

@ -50,6 +50,17 @@ class ContextTests(TestCase):
test_context['fruit']
self.assertIsNone(test_context.get('fruit'))
def test_flatten_context(self):
a = Context()
a.update({'a': 2})
a.update({'b': 4})
a.update({'c': 8})
self.assertEqual(a.flatten(), {
'False': False, 'None': None, 'True': True,
'a': 2, 'b': 4, 'c': 8
})
def test_context_comparable(self):
test_data = {'x': 'y', 'v': 'z', 'd': {'o': object, 'a': 'b'}}