Author: SmileyChris
Date: 2011-04-22 14:05:29 -0700 (Fri, 22 Apr 2011)
New Revision: 16089

Modified:
   django/branches/releases/1.3.X/django/template/context.py
   django/branches/releases/1.3.X/django/test/utils.py
   django/branches/releases/1.3.X/tests/regressiontests/templates/tests.py
Log:
[1.3.X] Fixes regression #15721 -- {% include %} and RequestContext not working 
together. Refs #15814.

Backport of r16031, plus the utility from r16030.

Modified: django/branches/releases/1.3.X/django/template/context.py
===================================================================
--- django/branches/releases/1.3.X/django/template/context.py   2011-04-22 
18:17:26 UTC (rev 16088)
+++ django/branches/releases/1.3.X/django/template/context.py   2011-04-22 
21:05:29 UTC (rev 16089)
@@ -14,21 +14,16 @@
     "pop() has been called more times than push()"
     pass
 
-class EmptyClass(object):
-    # No-op class which takes no args to its __init__ method, to help implement
-    # __copy__
-    pass
-
 class BaseContext(object):
     def __init__(self, dict_=None):
-        dict_ = dict_ or {}
-        self.dicts = [dict_]
+        self._reset_dicts(dict_)
 
+    def _reset_dicts(self, value=None):
+        self.dicts = [value or {}]
+
     def __copy__(self):
-        duplicate = EmptyClass()
-        duplicate.__class__ = self.__class__
-        duplicate.__dict__ = self.__dict__.copy()
-        duplicate.dicts = duplicate.dicts[:]
+        duplicate = copy(super(BaseContext, self))
+        duplicate.dicts = self.dicts[:]
         return duplicate
 
     def __repr__(self):
@@ -78,6 +73,15 @@
                 return d[key]
         return otherwise
 
+    def new(self, values=None):
+        """
+        Returns a new context with the same properties, but with only the
+        values given in 'values' stored.
+        """
+        new_context = copy(self)
+        new_context._reset_dicts(values)
+        return new_context
+
 class Context(BaseContext):
     "A stack container for variable context"
     def __init__(self, dict_=None, autoescape=True, current_app=None, 
use_l10n=None):
@@ -99,14 +103,6 @@
         self.dicts.append(other_dict)
         return other_dict
 
-    def new(self, values=None):
-        """
-        Returns a new Context with the same 'autoescape' value etc, but with
-        only the values given in 'values' stored.
-        """
-        return self.__class__(dict_=values, autoescape=self.autoescape,
-                              current_app=self.current_app, 
use_l10n=self.use_l10n)
-
 class RenderContext(BaseContext):
     """
     A stack container for storing Template state.

Modified: django/branches/releases/1.3.X/django/test/utils.py
===================================================================
--- django/branches/releases/1.3.X/django/test/utils.py 2011-04-22 18:17:26 UTC 
(rev 16088)
+++ django/branches/releases/1.3.X/django/test/utils.py 2011-04-22 21:05:29 UTC 
(rev 16089)
@@ -6,13 +6,16 @@
 from django.core import mail
 from django.core.mail.backends import locmem
 from django.test import signals
-from django.template import Template
+from django.template import Template, loader, TemplateDoesNotExist
+from django.template.loaders import cached
 from django.utils.translation import deactivate
 
 __all__ = ('Approximate', 'ContextList', 'setup_test_environment',
        'teardown_test_environment', 'get_runner')
 
+RESTORE_LOADERS_ATTR = '_original_template_source_loaders'
 
+
 class Approximate(object):
     def __init__(self, val, places=7):
         self.val = val
@@ -125,3 +128,41 @@
     test_module = __import__(test_module_name, {}, {}, test_path[-1])
     test_runner = getattr(test_module, test_path[-1])
     return test_runner
+
+
+def setup_test_template_loader(templates_dict, use_cached_loader=False):
+    """
+    Changes Django to only find templates from within a dictionary (where each
+    key is the template name and each value is the corresponding template
+    content to return).
+
+    Use meth:`restore_template_loaders` to restore the original loaders.
+    """
+    if hasattr(loader, RESTORE_LOADERS_ATTR):
+        raise Exception("loader.%s already exists" % RESTORE_LOADERS_ATTR)
+
+    def test_template_loader(template_name, template_dirs=None):
+        "A custom template loader that loads templates from a dictionary."
+        try:
+            return (templates_dict[template_name], "test:%s" % template_name)
+        except KeyError:
+            raise TemplateDoesNotExist(template_name)
+
+    if use_cached_loader:
+        template_loader = cached.Loader(('test_template_loader',))
+        template_loader._cached_loaders = (test_template_loader,)
+    else:
+        template_loader = test_template_loader
+
+    setattr(loader, RESTORE_LOADERS_ATTR, loader.template_source_loaders)
+    loader.template_source_loaders = (template_loader,)
+    return template_loader
+
+
+def restore_template_loaders():
+    """
+    Restores the original template loaders after
+    :meth:`setup_test_template_loader` has been run.
+    """
+    loader.template_source_loaders = getattr(loader, RESTORE_LOADERS_ATTR)
+    delattr(loader, RESTORE_LOADERS_ATTR)

Modified: 
django/branches/releases/1.3.X/tests/regressiontests/templates/tests.py
===================================================================
--- django/branches/releases/1.3.X/tests/regressiontests/templates/tests.py     
2011-04-22 18:17:26 UTC (rev 16088)
+++ django/branches/releases/1.3.X/tests/regressiontests/templates/tests.py     
2011-04-22 21:05:29 UTC (rev 16089)
@@ -17,6 +17,8 @@
 from django.core import urlresolvers
 from django.template import loader
 from django.template.loaders import app_directories, filesystem, cached
+from django.test.utils import setup_test_template_loader,\
+    restore_template_loaders
 from django.utils import unittest
 from django.utils.translation import activate, deactivate, ugettext as _
 from django.utils.safestring import mark_safe
@@ -1640,5 +1642,34 @@
         settings.INSTALLED_APPS = ('tagsegg',)
         t = template.Template(ttext)
 
+
+class RequestContextTests(BaseTemplateResponseTest):
+
+    def setUp(self):
+        templates = {
+            'child': Template('{{ var|default:"none" }}'),
+        }
+        setup_test_template_loader(templates)
+        self.fake_request = RequestFactory().get('/')
+
+    def tearDown(self):
+        restore_template_loaders()
+
+    def test_include_only(self):
+        """
+        Regression test for #15721, ``{% include %}`` and ``RequestContext``
+        not playing together nicely.
+        """
+        ctx = RequestContext(self.fake_request, {'var': 'parent'})
+        self.assertEqual(
+            template.Template('{% include "child" %}').render(ctx),
+            'parent'
+        )
+        self.assertEqual(
+            template.Template('{% include "child" only %}').render(ctx),
+            'none'
+        )
+
+
 if __name__ == "__main__":
     unittest.main()

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to