From c0010bf2ae4064c11cfee2387f6e06c3880fc6d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=C5=9Awica?= Date: Tue, 19 Apr 2016 17:59:16 +0200 Subject: [PATCH] Use COMPRESS_OFFLINE_CONTEXT in offline templates discovery Test case for template inheritance with variable from context and super Test case for template inheritance with variable from context --- compressor/management/commands/compress.py | 78 ++++++++++--------- compressor/offline/django.py | 16 ++-- compressor/offline/jinja2.py | 2 +- compressor/tests/test_offline.py | 42 +++++++++- .../base.html | 8 ++ .../test_compressor_offline.html | 1 + .../base1.html | 7 ++ .../base2.html | 7 ++ .../test_compressor_offline.html | 8 ++ .../base.html | 8 ++ .../test_compressor_offline.html | 1 + 11 files changed, 129 insertions(+), 49 deletions(-) create mode 100644 compressor/tests/test_templates/test_with_context_variable_inheritance/base.html create mode 100644 compressor/tests/test_templates/test_with_context_variable_inheritance/test_compressor_offline.html create mode 100644 compressor/tests/test_templates/test_with_context_variable_inheritance_super/base1.html create mode 100644 compressor/tests/test_templates/test_with_context_variable_inheritance_super/base2.html create mode 100644 compressor/tests/test_templates/test_with_context_variable_inheritance_super/test_compressor_offline.html create mode 100644 compressor/tests/test_templates_jinja2/test_with_context_variable_inheritance/base.html create mode 100644 compressor/tests/test_templates_jinja2/test_with_context_variable_inheritance/test_compressor_offline.html diff --git a/compressor/management/commands/compress.py b/compressor/management/commands/compress.py index a664822..230ecba 100644 --- a/compressor/management/commands/compress.py +++ b/compressor/management/commands/compress.py @@ -2,7 +2,7 @@ import os import sys -from collections import OrderedDict +from collections import OrderedDict, defaultdict from fnmatch import fnmatch from importlib import import_module @@ -154,6 +154,18 @@ class Command(BaseCommand): if verbosity > 1: log.write("Found templates:\n\t" + "\n\t".join(templates) + "\n") + contexts = settings.COMPRESS_OFFLINE_CONTEXT + if isinstance(contexts, six.string_types): + try: + module, function = get_mod_func(contexts) + contexts = getattr(import_module(module), function)() + except (AttributeError, ImportError, TypeError) as e: + raise ImportError("Couldn't import offline context function %s: %s" % + (settings.COMPRESS_OFFLINE_CONTEXT, e)) + elif not isinstance(contexts, (list, tuple)): + contexts = [contexts] + contexts = list(contexts) # evaluate generator + parser = self.__get_parser(engine) compressor_nodes = OrderedDict() for template_name in templates: @@ -176,16 +188,22 @@ class Command(BaseCommand): log.write("UnicodeDecodeError while trying to read " "template %s\n" % template_name) continue - try: - nodes = list(parser.walk_nodes(template)) - except (TemplateDoesNotExist, TemplateSyntaxError) as e: - # Could be an error in some base template - if verbosity > 0: - log.write("Error parsing template %s: %s\n" % (template_name, e)) - continue - if nodes: - template.template_name = template_name - compressor_nodes.setdefault(template, []).extend(nodes) + + for context_dict in contexts: + context = parser.get_init_context(context_dict) + context = Context(context) + try: + nodes = list(parser.walk_nodes(template, context=context)) + except (TemplateDoesNotExist, TemplateSyntaxError) as e: + # Could be an error in some base template + if verbosity > 0: + log.write("Error parsing template %s: %s\n" % (template_name, e)) + continue + if nodes: + template.template_name = template_name + template_nodes = compressor_nodes.setdefault(template, OrderedDict()) + for node in nodes: + template_nodes.setdefault(node, []).append(context) if not compressor_nodes: raise OfflineGenerationError( @@ -198,36 +216,23 @@ class Command(BaseCommand): "\n\t".join((t.template_name for t in compressor_nodes.keys())) + "\n") - contexts = settings.COMPRESS_OFFLINE_CONTEXT - if isinstance(contexts, six.string_types): - try: - module, function = get_mod_func(contexts) - contexts = getattr(import_module(module), function)() - except (AttributeError, ImportError, TypeError) as e: - raise ImportError("Couldn't import offline context function %s: %s" % - (settings.COMPRESS_OFFLINE_CONTEXT, e)) - elif not isinstance(contexts, (list, tuple)): - contexts = [contexts] - log.write("Compressing... ") - block_count = context_count = 0 + block_count = 0 + compressed_contexts = [] results = [] offline_manifest = OrderedDict() + for template, nodes in compressor_nodes.items(): + template._log = log + template._log_verbosity = verbosity - for context_dict in contexts: - context_count += 1 - init_context = parser.get_init_context(context_dict) - - for template, nodes in compressor_nodes.items(): - context = Context(init_context) - template._log = log - template._log_verbosity = verbosity - - if not parser.process_template(template, context): - continue - - for node in nodes: + for node, contexts in nodes.items(): + for context in contexts: + if context not in compressed_contexts: + compressed_contexts.append(context) context.push() + if not parser.process_template(template, context): + continue + parser.process_node(template, context, node) rendered = parser.render_nodelist(template, context, node) key = get_offline_hexdigest(rendered) @@ -247,6 +252,7 @@ class Command(BaseCommand): write_offline_manifest(offline_manifest) + context_count = len(compressed_contexts) log.write("done\nCompressed %d block(s) from %d template(s) for %d context(s).\n" % (block_count, len(compressor_nodes), context_count)) return block_count, results diff --git a/compressor/offline/django.py b/compressor/offline/django.py index 0cae086..620e75c 100644 --- a/compressor/offline/django.py +++ b/compressor/offline/django.py @@ -116,16 +116,12 @@ class DjangoParser(object): def render_node(self, template, context, node): return node.render(context, forced=True) - def get_nodelist(self, node, original): + def get_nodelist(self, node, original, context): if isinstance(node, ExtendsNode): try: - context = Context() + if context is None: + context = Context() context.template = original - # TODO: We are passing an empty context when finding base - # templates. This does not work when extending using - # variables ({% extends template_var %}). - # A refactor might be needed to support that use-case with - # multiple offline contexts. return handle_extendsnode(node, context) except template.TemplateSyntaxError as e: raise TemplateSyntaxError(str(e)) @@ -141,13 +137,13 @@ class DjangoParser(object): nodelist = getattr(node, 'nodelist', []) return nodelist - def walk_nodes(self, node, original=None): + def walk_nodes(self, node, original=None, context=None): if original is None: original = node - for node in self.get_nodelist(node, original): + for node in self.get_nodelist(node, original, context): if isinstance(node, CompressorNode) \ and node.is_offline_compression_enabled(forced=True): yield node else: - for node in self.walk_nodes(node, original): + for node in self.walk_nodes(node, original, context): yield node diff --git a/compressor/offline/jinja2.py b/compressor/offline/jinja2.py index feee818..eb896ba 100644 --- a/compressor/offline/jinja2.py +++ b/compressor/offline/jinja2.py @@ -112,7 +112,7 @@ class Jinja2Parser(object): return body - def walk_nodes(self, node, block_name=None): + def walk_nodes(self, node, block_name=None, context=None): for node in self.get_nodelist(node): if (isinstance(node, CallBlock) and isinstance(node.call, Call) and diff --git a/compressor/tests/test_offline.py b/compressor/tests/test_offline.py index e5728dc..4620685 100644 --- a/compressor/tests/test_offline.py +++ b/compressor/tests/test_offline.py @@ -120,10 +120,14 @@ class OfflineTestCaseMixin(object): default_storage.delete(manifest_path) def _prepare_contexts(self, engine): + contexts = settings.COMPRESS_OFFLINE_CONTEXT + if not isinstance(contexts, (list, tuple)): + contexts = [contexts] + if engine == 'django': - return [Context(settings.COMPRESS_OFFLINE_CONTEXT)] + return [Context(c) for c in contexts] if engine == 'jinja2': - return [settings.COMPRESS_OFFLINE_CONTEXT] + return contexts return None def _render_template(self, engine): @@ -433,6 +437,40 @@ class OfflineCompressTestCaseWithContextGeneratorSuper( engines = ('django',) +class OfflineCompressTestCaseWithContextVariableInheritance( + OfflineTestCaseMixin, TestCase): + templates_dir = 'test_with_context_variable_inheritance' + additional_test_settings = { + 'COMPRESS_OFFLINE_CONTEXT': { + 'parent_template': 'base.html', + } + } + + def _test_offline(self, engine): + count, result = CompressCommand().compress( + log=self.log, verbosity=self.verbosity, engine=engine) + self.assertEqual(1, count) + self.assertEqual([''], result) + rendered_template = self._render_template(engine) + self.assertEqual(rendered_template, '\n' + result[0] + '\n') + + +class OfflineCompressTestCaseWithContextVariableInheritanceSuper( + OfflineTestCaseMixin, TestCase): + templates_dir = 'test_with_context_variable_inheritance_super' + additional_test_settings = { + 'COMPRESS_OFFLINE_CONTEXT': [{ + 'parent_template': 'base1.html', + }, { + 'parent_template': 'base2.html', + }] + } + expected_hash = ['7d1416cab12e', 'a31eb23d0157'] + # Block.super not supported for Jinja2 yet. + engines = ('django',) + + class OfflineCompressTestCaseWithContextGeneratorImportError( OfflineTestCaseMixin, TestCase): templates_dir = 'test_with_context' diff --git a/compressor/tests/test_templates/test_with_context_variable_inheritance/base.html b/compressor/tests/test_templates/test_with_context_variable_inheritance/base.html new file mode 100644 index 0000000..27fc3a6 --- /dev/null +++ b/compressor/tests/test_templates/test_with_context_variable_inheritance/base.html @@ -0,0 +1,8 @@ +{% load compress %} +{% spaceless %} + {% compress js %} + + {% endcompress %} +{% endspaceless %} diff --git a/compressor/tests/test_templates/test_with_context_variable_inheritance/test_compressor_offline.html b/compressor/tests/test_templates/test_with_context_variable_inheritance/test_compressor_offline.html new file mode 100644 index 0000000..9879c65 --- /dev/null +++ b/compressor/tests/test_templates/test_with_context_variable_inheritance/test_compressor_offline.html @@ -0,0 +1 @@ +{% extends parent_template %} diff --git a/compressor/tests/test_templates/test_with_context_variable_inheritance_super/base1.html b/compressor/tests/test_templates/test_with_context_variable_inheritance_super/base1.html new file mode 100644 index 0000000..ca0748a --- /dev/null +++ b/compressor/tests/test_templates/test_with_context_variable_inheritance_super/base1.html @@ -0,0 +1,7 @@ +{% spaceless %} +{% block js %} + +{% endblock %} +{% endspaceless %} diff --git a/compressor/tests/test_templates/test_with_context_variable_inheritance_super/base2.html b/compressor/tests/test_templates/test_with_context_variable_inheritance_super/base2.html new file mode 100644 index 0000000..23434c1 --- /dev/null +++ b/compressor/tests/test_templates/test_with_context_variable_inheritance_super/base2.html @@ -0,0 +1,7 @@ +{% spaceless %} +{% block js %} + +{% endblock %} +{% endspaceless %} diff --git a/compressor/tests/test_templates/test_with_context_variable_inheritance_super/test_compressor_offline.html b/compressor/tests/test_templates/test_with_context_variable_inheritance_super/test_compressor_offline.html new file mode 100644 index 0000000..179ddd3 --- /dev/null +++ b/compressor/tests/test_templates/test_with_context_variable_inheritance_super/test_compressor_offline.html @@ -0,0 +1,8 @@ +{% extends parent_template %} +{% load compress %} + +{% block js %}{% spaceless %} + {% compress js %} + {{ block.super }} + {% endcompress %} +{% endspaceless %}{% endblock %} diff --git a/compressor/tests/test_templates_jinja2/test_with_context_variable_inheritance/base.html b/compressor/tests/test_templates_jinja2/test_with_context_variable_inheritance/base.html new file mode 100644 index 0000000..ef17a57 --- /dev/null +++ b/compressor/tests/test_templates_jinja2/test_with_context_variable_inheritance/base.html @@ -0,0 +1,8 @@ + +{% spaceless %} + {% compress js %} + + {% endcompress %} +{% endspaceless %} diff --git a/compressor/tests/test_templates_jinja2/test_with_context_variable_inheritance/test_compressor_offline.html b/compressor/tests/test_templates_jinja2/test_with_context_variable_inheritance/test_compressor_offline.html new file mode 100644 index 0000000..9879c65 --- /dev/null +++ b/compressor/tests/test_templates_jinja2/test_with_context_variable_inheritance/test_compressor_offline.html @@ -0,0 +1 @@ +{% extends parent_template %}