Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #198 from diox/develop

Make {{ block.super }} in compress management command a little more robust
  • Loading branch information...
commit d63cf0e6a3e3f75fa4363c10cd21d6448719933e 2 parents 40a9fc3 + 480e7d0
Jannis Leidel authored
View
89 compressor/management/commands/compress.py
@@ -28,12 +28,62 @@
from compressor.templatetags.compress import CompressorNode
from compressor.utils import walk, any
+def patched__render(self, context):
+ # 'Fake' _render method that just returns the context instead of rendering.
+ # It also checks whether the first node is an extend node or not, to be able
+ # to handle complex inheritance chain.
+ self._render_firstnode = MethodType(patched__render_firstnode, self)
+ self._render_firstnode(context)
+ return context
+
+def patched__render_firstnode(self, context):
+ # If this template has a ExtendsNode, we want to find out what
+ # should be put in render_context to make the {% block ... %}
+ # tags work.
+ #
+ # We can't fully render the base template(s) (we don't have the
+ # full context vars - only what's necessary to render the compress
+ # nodes!), therefore we hack the ExtendsNode we found, patching
+ # its get_parent method so that rendering the ExtendsNode only
+ # gives us the blocks content without doing any actual rendering.
+ extra_context = {}
+ firstnode = self.nodelist[0]
+ if isinstance(firstnode, ExtendsNode):
+ firstnode._log = self._log
+ firstnode._log_verbosity = self._log_verbosity
+ firstnode._old_get_parent = firstnode.get_parent
+ firstnode.get_parent = MethodType(patched_get_parent, firstnode)
+ try:
+ extra_context = firstnode.render(context)
+ context.render_context = extra_context.render_context
+ # We aren't rendering {% block %} tags, but we want {{ block.super }}
+ # inside {% compress %} inside {% block %}s to work. Therefore, we
+ # need to pop() the last block context for each block name, to
+ # emulate what would have been done if the {% block %} had been fully
+ # rendered.
+ for blockname in firstnode.blocks.keys():
+ context.render_context[BLOCK_CONTEXT_KEY].pop(blockname)
+ except (IOError, TemplateSyntaxError, TemplateDoesNotExist):
+ # That first node we are trying to render might cause more errors
+ # that we didn't catch when simply creating a Template instance
+ # above, so we need to catch that (and ignore it, just like above)
+ # as well.
+ if self._log_verbosity > 0:
+ self._log.write("Caught error when rendering extend node from \
+ template %s\n" % template.template_name)
+ return None
+ return extra_context
def patched_get_parent(self, context):
- # Patch template returned by get_parent to make sure their _render method is
- # just returning the context instead of actually rendering stuff.
+ # Patch template returned by extendsnode's get_parent to make sure their
+ # _render method is just returning the context instead of actually
+ # rendering stuff.
+ # In addition, this follows the inheritance chain by looking if the first
+ # node of the template is an extend node itself.
compiled_template = self._old_get_parent(context)
- compiled_template._render = MethodType(lambda self, c: c, compiled_template)
+ compiled_template._log = self._log
+ compiled_template._log_verbosity = self._log_verbosity
+ compiled_template._render = MethodType(patched__render, compiled_template)
return compiled_template
@@ -189,32 +239,19 @@ def compress(self, log=None, **options):
offline_manifest = {}
for template, nodes in compressor_nodes.iteritems():
context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
- extra_context = {}
- firstnode = template.nodelist[0]
- if isinstance(firstnode, ExtendsNode):
- # If this template has a ExtendsNode, we apply our patch to
- # generate the necessary context, and then use it for all the
- # nodes in it, just in case (we don't know which nodes were
- # in a block)
- firstnode._old_get_parent = firstnode.get_parent
- firstnode.get_parent = MethodType(patched_get_parent, firstnode)
- try:
- extra_context = firstnode.render(context)
- context.render_context = extra_context.render_context
- except (IOError, TemplateSyntaxError, TemplateDoesNotExist):
- # That first node we are trying to render might cause more errors
- # that we didn't catch when simply creating a Template instance
- # above, so we need to catch that (and ignore it, just like above)
- # as well.
- if verbosity > 0:
- log.write("Caught error when rendering extend node "
- "from template %s\n" %
- template.template_name)
- continue
+ template._log = log
+ template._log_verbosity = verbosity
+ template._render_firstnode = MethodType(patched__render_firstnode, template)
+ extra_context = template._render_firstnode(context)
+ if extra_context is None:
+ # Something is wrong - ignore this template
+ continue
for node in nodes:
context.push()
if extra_context and node._block_name:
- context['block'] = context.render_context[BLOCK_CONTEXT_KEY].pop(node._block_name)
+ # Give a block context to the node if it was found inside
+ # a {% block %}.
+ context['block'] = context.render_context[BLOCK_CONTEXT_KEY].get_block(node._block_name)
if context['block']:
context['block'].context = context
key = get_offline_hexdigest(node.nodelist.render(context))
View
11 compressor/tests/__init__.py
@@ -5,9 +5,14 @@
CssDataUriTestCase, TemplateTestCase)
from compressor.tests.jinja2ext import TestJinja2CompressorExtension
from compressor.tests.offline import (
- OfflineGenerationBlockSuperTestCase, OfflineGenerationConditionTestCase,
- OfflineGenerationTemplateTagTestCase, OfflineGenerationTestCaseWithContext,
- OfflineGenerationTestCaseErrors, OfflineGenerationTestCase)
+ OfflineGenerationBlockSuperTestCase,
+ OfflineGenerationBlockSuperTestCaseWithExtraContent,
+ OfflineGenerationBlockSuperMultipleTestCase,
+ OfflineGenerationConditionTestCase,
+ OfflineGenerationTemplateTagTestCase,
+ OfflineGenerationTestCaseWithContext,
+ OfflineGenerationTestCaseErrors,
+ OfflineGenerationTestCase)
from compressor.tests.parsers import (LxmlParserTests, Html5LibParserTests,
BeautifulSoupParserTests, HtmlParserTests)
from compressor.tests.signals import PostCompressSignalTestCase
View
19 compressor/tests/offline.py
@@ -67,6 +67,25 @@ class OfflineGenerationBlockSuperTestCase(OfflineTestCaseMixin, TestCase):
templates_dir = "test_block_super"
expected_hash = "7c02d201f69d"
+
+class OfflineGenerationBlockSuperMultipleTestCase(OfflineTestCaseMixin, TestCase):
+ templates_dir = "test_block_super_multiple"
+ expected_hash = "2f6ef61c488e"
+
+
+class OfflineGenerationBlockSuperTestCaseWithExtraContent(OfflineTestCaseMixin, TestCase):
+ templates_dir = "test_block_super_extra"
+
+ def test_offline(self):
+ count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity)
+ self.assertEqual(2, count)
+ self.assertEqual([
+ u'<script type="text/javascript" src="/media/CACHE/js/ced14aec5856.js"></script>',
+ u'<script type="text/javascript" src="/media/CACHE/js/7c02d201f69d.js"></script>'
+ ], result)
+ rendered_template = self.template.render(Context(settings.COMPRESS_OFFLINE_CONTEXT))
+ self.assertEqual(rendered_template, "".join(result) + "\n")
+
class OfflineGenerationConditionTestCase(OfflineTestCaseMixin, TestCase):
templates_dir = "test_condition"
View
15 compressor/tests/test_templates/test_block_super_extra/base.html
@@ -0,0 +1,15 @@
+{% spaceless %}
+{% block js %}
+ <script type="text/javascript">
+ alert("test using block.super");
+ </script>
+{% endblock %}
+
+{% block css %}
+ <style type="text/css">
+ body {
+ background: red;
+ }
+ </style>
+{% endblock %}
+{% endspaceless %}
View
19 compressor/tests/test_templates/test_block_super_extra/test_compressor_offline.html
@@ -0,0 +1,19 @@
+{% extends "base.html" %}
+{% load compress %}
+
+{% block js %}{% spaceless %}
+ {% compress js %}
+ <script type="text/javascript">
+ alert("this alert should be alone.");
+ </script>
+ {% endcompress %}
+
+ {% compress js %}
+ {{ block.super }}
+ <script type="text/javascript">
+ alert("this alert shouldn't be alone!");
+ </script>
+ {% endcompress %}
+{% endspaceless %}{% endblock %}
+
+{% block css %}{% endblock %}
View
15 compressor/tests/test_templates/test_block_super_multiple/base.html
@@ -0,0 +1,15 @@
+{% spaceless %}
+{% block js %}
+ <script type="text/javascript">
+ alert("test using multiple inheritance and block.super");
+ </script>
+{% endblock %}
+
+{% block css %}
+ <style type="text/css">
+ body {
+ background: red;
+ }
+ </style>
+{% endblock %}
+{% endspaceless %}
View
3  compressor/tests/test_templates/test_block_super_multiple/base2.html
@@ -0,0 +1,3 @@
+{% extends "base.html" %}
+
+{% block css %}{% endblock %}
View
11 compressor/tests/test_templates/test_block_super_multiple/test_compressor_offline.html
@@ -0,0 +1,11 @@
+{% extends "base2.html" %}
+{% load compress %}
+
+{% block js %}{% spaceless %}
+ {% compress js %}
+ {{ block.super }}
+ <script type="text/javascript">
+ alert("this alert shouldn't be alone!");
+ </script>
+ {% endcompress %}
+{% endspaceless %}{% endblock %}
Please sign in to comment.
Something went wrong with that request. Please try again.