Merge pull request #758 from grzegorzswica/support-inheritance-in-offline-compression-using-a-variable
#674 Support inheritance in offline compression using a variable
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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(['<script type="text/javascript" src="/static/CACHE/js/'
|
||||
'ea3267f3e9dd.js"></script>'], 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'
|
||||
|
@@ -0,0 +1,8 @@
|
||||
{% load compress %}
|
||||
{% spaceless %}
|
||||
{% compress js %}
|
||||
<script type="text/javascript">
|
||||
alert("test using template extension passed in variable parent=base.html");
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endspaceless %}
|
@@ -0,0 +1 @@
|
||||
{% extends parent_template %}
|
@@ -0,0 +1,7 @@
|
||||
{% spaceless %}
|
||||
{% block js %}
|
||||
<script type="text/javascript">
|
||||
alert("test using template extension passed in variable parent=base1.html");
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endspaceless %}
|
@@ -0,0 +1,7 @@
|
||||
{% spaceless %}
|
||||
{% block js %}
|
||||
<script type="text/javascript">
|
||||
alert("test using template extension passed in variable parent=base2.html");
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endspaceless %}
|
@@ -0,0 +1,8 @@
|
||||
{% extends parent_template %}
|
||||
{% load compress %}
|
||||
|
||||
{% block js %}{% spaceless %}
|
||||
{% compress js %}
|
||||
{{ block.super }}
|
||||
{% endcompress %}
|
||||
{% endspaceless %}{% endblock %}
|
@@ -0,0 +1,8 @@
|
||||
|
||||
{% spaceless %}
|
||||
{% compress js %}
|
||||
<script type="text/javascript">
|
||||
alert("test using template extension passed in variable parent=base.html");
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endspaceless %}
|
@@ -0,0 +1 @@
|
||||
{% extends parent_template %}
|
Reference in New Issue
Block a user