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.