Commit 8274fa60 authored by Marek Wywiał's avatar Marek Wywiał Committed by Baptiste Mispelon
Browse files

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

That method was introduced in 9db4271b.

Refs #21765.
parent 57ba5bf9
Loading
Loading
Loading
Loading
+10 −7
Original line number Diff line number Diff line
@@ -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
+37 −0
Original line number Diff line number Diff line
@@ -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
+8 −0
Original line number Diff line number Diff line
@@ -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.

+11 −0
Original line number Diff line number Diff line
@@ -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'}}