@@ -36,17 +36,19 @@ class Compressor(object):
|
|||||||
Base compressor object to be subclassed for content type
|
Base compressor object to be subclassed for content type
|
||||||
depending implementations details.
|
depending implementations details.
|
||||||
"""
|
"""
|
||||||
type = None
|
|
||||||
|
|
||||||
def __init__(self, content=None, output_prefix=None, context=None, *args, **kwargs):
|
def __init__(self, content=None, output_prefix=None,
|
||||||
|
context=None, filters=None, *args, **kwargs):
|
||||||
self.content = content or "" # rendered contents of {% compress %} tag
|
self.content = content or "" # rendered contents of {% compress %} tag
|
||||||
self.output_prefix = output_prefix or "compressed"
|
self.output_prefix = output_prefix or "compressed"
|
||||||
self.output_dir = settings.COMPRESS_OUTPUT_DIR.strip('/')
|
self.output_dir = settings.COMPRESS_OUTPUT_DIR.strip('/')
|
||||||
self.charset = settings.DEFAULT_CHARSET
|
self.charset = settings.DEFAULT_CHARSET
|
||||||
self.split_content = []
|
self.split_content = []
|
||||||
self.context = context or {}
|
self.context = context or {}
|
||||||
|
self.type = output_prefix or ""
|
||||||
|
self.filters = filters or []
|
||||||
self.extra_context = {}
|
self.extra_context = {}
|
||||||
self.all_mimetypes = dict(settings.COMPRESS_PRECOMPILERS)
|
self.precompiler_mimetypes = dict(settings.COMPRESS_PRECOMPILERS)
|
||||||
self.finders = staticfiles.finders
|
self.finders = staticfiles.finders
|
||||||
self._storage = None
|
self._storage = None
|
||||||
|
|
||||||
@@ -205,7 +207,7 @@ class Compressor(object):
|
|||||||
options = dict(options, filename=value)
|
options = dict(options, filename=value)
|
||||||
value = self.get_filecontent(value, charset)
|
value = self.get_filecontent(value, charset)
|
||||||
|
|
||||||
if self.all_mimetypes:
|
if self.precompiler_mimetypes:
|
||||||
precompiled, value = self.precompile(value, **options)
|
precompiled, value = self.precompile(value, **options)
|
||||||
|
|
||||||
if enabled:
|
if enabled:
|
||||||
@@ -245,14 +247,17 @@ class Compressor(object):
|
|||||||
return False, content
|
return False, content
|
||||||
attrs = self.parser.elem_attribs(elem)
|
attrs = self.parser.elem_attribs(elem)
|
||||||
mimetype = attrs.get("type", None)
|
mimetype = attrs.get("type", None)
|
||||||
if mimetype:
|
if mimetype is None:
|
||||||
filter_or_command = self.all_mimetypes.get(mimetype)
|
return False, content
|
||||||
|
|
||||||
|
filter_or_command = self.precompiler_mimetypes.get(mimetype)
|
||||||
if filter_or_command is None:
|
if filter_or_command is None:
|
||||||
if mimetype not in ("text/css", "text/javascript"):
|
if mimetype in ("text/css", "text/javascript"):
|
||||||
|
return False, content
|
||||||
raise CompressorError("Couldn't find any precompiler in "
|
raise CompressorError("Couldn't find any precompiler in "
|
||||||
"COMPRESS_PRECOMPILERS setting for "
|
"COMPRESS_PRECOMPILERS setting for "
|
||||||
"mimetype '%s'." % mimetype)
|
"mimetype '%s'." % mimetype)
|
||||||
else:
|
|
||||||
mod_name, cls_name = get_mod_func(filter_or_command)
|
mod_name, cls_name = get_mod_func(filter_or_command)
|
||||||
try:
|
try:
|
||||||
mod = import_module(mod_name)
|
mod = import_module(mod_name)
|
||||||
@@ -264,16 +269,12 @@ class Compressor(object):
|
|||||||
try:
|
try:
|
||||||
precompiler_class = getattr(mod, cls_name)
|
precompiler_class = getattr(mod, cls_name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise FilterDoesNotExist('Could not find "%s".' %
|
raise FilterDoesNotExist('Could not find "%s".' % filter_or_command)
|
||||||
filter_or_command)
|
|
||||||
else:
|
|
||||||
filter = precompiler_class(
|
filter = precompiler_class(
|
||||||
content, attrs, filter_type=self.type, charset=charset,
|
content, attrs, filter_type=self.type, charset=charset,
|
||||||
filename=filename)
|
filename=filename)
|
||||||
return True, filter.input(**kwargs)
|
return True, filter.input(**kwargs)
|
||||||
|
|
||||||
return False, content
|
|
||||||
|
|
||||||
def filter(self, content, method, **kwargs):
|
def filter(self, content, method, **kwargs):
|
||||||
for filter_cls in self.cached_filters:
|
for filter_cls in self.cached_filters:
|
||||||
filter_func = getattr(
|
filter_func = getattr(
|
||||||
|
@@ -5,10 +5,8 @@ from compressor.conf import settings
|
|||||||
class CssCompressor(Compressor):
|
class CssCompressor(Compressor):
|
||||||
|
|
||||||
def __init__(self, content=None, output_prefix="css", context=None):
|
def __init__(self, content=None, output_prefix="css", context=None):
|
||||||
super(CssCompressor, self).__init__(content=content,
|
filters = list(settings.COMPRESS_CSS_FILTERS)
|
||||||
output_prefix=output_prefix, context=context)
|
super(CssCompressor, self).__init__(content, output_prefix, context, filters)
|
||||||
self.filters = list(settings.COMPRESS_CSS_FILTERS)
|
|
||||||
self.type = output_prefix
|
|
||||||
|
|
||||||
def split_contents(self):
|
def split_contents(self):
|
||||||
if self.split_content:
|
if self.split_content:
|
||||||
|
@@ -5,9 +5,8 @@ from compressor.base import Compressor, SOURCE_HUNK, SOURCE_FILE
|
|||||||
class JsCompressor(Compressor):
|
class JsCompressor(Compressor):
|
||||||
|
|
||||||
def __init__(self, content=None, output_prefix="js", context=None):
|
def __init__(self, content=None, output_prefix="js", context=None):
|
||||||
super(JsCompressor, self).__init__(content, output_prefix, context)
|
filters = list(settings.COMPRESS_JS_FILTERS)
|
||||||
self.filters = list(settings.COMPRESS_JS_FILTERS)
|
super(JsCompressor, self).__init__(content, output_prefix, context, filters)
|
||||||
self.type = output_prefix
|
|
||||||
|
|
||||||
def split_contents(self):
|
def split_contents(self):
|
||||||
if self.split_content:
|
if self.split_content:
|
||||||
|
@@ -40,8 +40,7 @@ class CompressorMixin(object):
|
|||||||
|
|
||||||
def debug_mode(self, context):
|
def debug_mode(self, context):
|
||||||
if settings.COMPRESS_DEBUG_TOGGLE:
|
if settings.COMPRESS_DEBUG_TOGGLE:
|
||||||
# Only check for the debug parameter
|
# Only check for the debug parameter if a RequestContext was used
|
||||||
# if a RequestContext was used
|
|
||||||
request = context.get('request', None)
|
request = context.get('request', None)
|
||||||
if request is not None:
|
if request is not None:
|
||||||
return settings.COMPRESS_DEBUG_TOGGLE in request.GET
|
return settings.COMPRESS_DEBUG_TOGGLE in request.GET
|
||||||
@@ -57,12 +56,11 @@ class CompressorMixin(object):
|
|||||||
return (settings.COMPRESS_ENABLED and
|
return (settings.COMPRESS_ENABLED and
|
||||||
settings.COMPRESS_OFFLINE) or forced
|
settings.COMPRESS_OFFLINE) or forced
|
||||||
|
|
||||||
def render_offline(self, context, forced):
|
def render_offline(self, context):
|
||||||
"""
|
"""
|
||||||
If enabled and in offline mode, and not forced check the offline cache
|
If enabled and in offline mode, and not forced check the offline cache
|
||||||
and return the result if given
|
and return the result if given
|
||||||
"""
|
"""
|
||||||
if self.is_offline_compression_enabled(forced) and not forced:
|
|
||||||
key = get_offline_hexdigest(self.get_original_content(context))
|
key = get_offline_hexdigest(self.get_original_content(context))
|
||||||
offline_manifest = get_offline_manifest()
|
offline_manifest = get_offline_manifest()
|
||||||
if key in offline_manifest:
|
if key in offline_manifest:
|
||||||
@@ -72,46 +70,42 @@ class CompressorMixin(object):
|
|||||||
'enabled but key "%s" is missing from offline manifest. '
|
'enabled but key "%s" is missing from offline manifest. '
|
||||||
'You may need to run "python manage.py compress".' % key)
|
'You may need to run "python manage.py compress".' % key)
|
||||||
|
|
||||||
def render_cached(self, compressor, kind, mode, forced=False):
|
def render_cached(self, compressor, kind, mode):
|
||||||
"""
|
"""
|
||||||
If enabled checks the cache for the given compressor's cache key
|
If enabled checks the cache for the given compressor's cache key
|
||||||
and return a tuple of cache key and output
|
and return a tuple of cache key and output
|
||||||
"""
|
"""
|
||||||
if settings.COMPRESS_ENABLED and not forced:
|
|
||||||
cache_key = get_templatetag_cachekey(compressor, mode, kind)
|
cache_key = get_templatetag_cachekey(compressor, mode, kind)
|
||||||
cache_content = cache_get(cache_key)
|
cache_content = cache_get(cache_key)
|
||||||
return cache_key, cache_content
|
return cache_key, cache_content
|
||||||
return None, None
|
|
||||||
|
|
||||||
def render_compressed(self, context, kind, mode, forced=False):
|
def render_compressed(self, context, kind, mode, forced=False):
|
||||||
|
|
||||||
# See if it has been rendered offline
|
# See if it has been rendered offline
|
||||||
cached_offline = self.render_offline(context, forced=forced)
|
if self.is_offline_compression_enabled(forced) and not forced:
|
||||||
if cached_offline:
|
return self.render_offline(context)
|
||||||
return cached_offline
|
|
||||||
|
|
||||||
# Take a shortcut if we really don't have anything to do
|
# Take a shortcut if we really don't have anything to do
|
||||||
if ((not settings.COMPRESS_ENABLED and
|
if (not settings.COMPRESS_ENABLED and
|
||||||
not settings.COMPRESS_PRECOMPILERS) and not forced):
|
not settings.COMPRESS_PRECOMPILERS and not forced):
|
||||||
return self.get_original_content(context)
|
return self.get_original_content(context)
|
||||||
|
|
||||||
context['compressed'] = {'name': getattr(self, 'name', None)}
|
context['compressed'] = {'name': getattr(self, 'name', None)}
|
||||||
compressor = self.get_compressor(context, kind)
|
compressor = self.get_compressor(context, kind)
|
||||||
|
|
||||||
# Prepare the actual compressor and check cache
|
# Check cache
|
||||||
cache_key, cache_content = self.render_cached(compressor, kind, mode, forced=forced)
|
cache_key = None
|
||||||
|
if settings.COMPRESS_ENABLED and not forced:
|
||||||
|
cache_key, cache_content = self.render_cached(compressor, kind, mode)
|
||||||
if cache_content is not None:
|
if cache_content is not None:
|
||||||
return cache_content
|
return cache_content
|
||||||
|
|
||||||
rendered_output = self.render_output(compressor, mode, forced=forced)
|
rendered_output = compressor.output(mode, forced=forced)
|
||||||
assert isinstance(rendered_output, six.string_types)
|
assert isinstance(rendered_output, six.string_types)
|
||||||
if cache_key:
|
if cache_key:
|
||||||
cache_set(cache_key, rendered_output)
|
cache_set(cache_key, rendered_output)
|
||||||
return rendered_output
|
return rendered_output
|
||||||
|
|
||||||
def render_output(self, compressor, mode, forced=False):
|
|
||||||
return compressor.output(mode, forced=forced)
|
|
||||||
|
|
||||||
|
|
||||||
class CompressorNode(CompressorMixin, template.Node):
|
class CompressorNode(CompressorMixin, template.Node):
|
||||||
|
|
||||||
@@ -124,14 +118,6 @@ class CompressorNode(CompressorMixin, template.Node):
|
|||||||
def get_original_content(self, context):
|
def get_original_content(self, context):
|
||||||
return self.nodelist.render(context)
|
return self.nodelist.render(context)
|
||||||
|
|
||||||
def debug_mode(self, context):
|
|
||||||
if settings.COMPRESS_DEBUG_TOGGLE:
|
|
||||||
# Only check for the debug parameter
|
|
||||||
# if a RequestContext was used
|
|
||||||
request = context.get('request', None)
|
|
||||||
if request is not None:
|
|
||||||
return settings.COMPRESS_DEBUG_TOGGLE in request.GET
|
|
||||||
|
|
||||||
def render(self, context, forced=False):
|
def render(self, context, forced=False):
|
||||||
|
|
||||||
# Check if in debug mode
|
# Check if in debug mode
|
||||||
|
@@ -12,4 +12,4 @@ class FinderTestCase(TestCase):
|
|||||||
|
|
||||||
def test_list_returns_empty_list(self):
|
def test_list_returns_empty_list(self):
|
||||||
finder = CompressorFinder()
|
finder = CompressorFinder()
|
||||||
self.assertEquals(finder.list([]), [])
|
self.assertEqual(finder.list([]), [])
|
||||||
|
@@ -358,6 +358,24 @@ class OfflineGenerationTestCase(OfflineTestCaseMixin, TestCase):
|
|||||||
settings.TEMPLATE_LOADERS = old_loaders
|
settings.TEMPLATE_LOADERS = old_loaders
|
||||||
|
|
||||||
|
|
||||||
|
class OfflineGenerationEmptyTag(OfflineTestCaseMixin, TestCase):
|
||||||
|
"""
|
||||||
|
In case of a compress template tag with no content, an entry
|
||||||
|
will be added to the manifest with an empty string as value.
|
||||||
|
This test makes sure there is no recompression happening when
|
||||||
|
compressor encounters such an emptystring in the manifest.
|
||||||
|
"""
|
||||||
|
templates_dir = "basic"
|
||||||
|
expected_hash = "f5e179b8eca4"
|
||||||
|
engines = ("django",)
|
||||||
|
|
||||||
|
def _test_offline(self, engine):
|
||||||
|
count, result = CompressCommand().compress(log=self.log, verbosity=self.verbosity, engine=engine)
|
||||||
|
manifest = get_offline_manifest()
|
||||||
|
manifest[list(manifest)[0]] = ""
|
||||||
|
self.assertEqual(self._render_template(engine), "\n")
|
||||||
|
|
||||||
|
|
||||||
class OfflineGenerationBlockSuperBaseCompressed(OfflineTestCaseMixin, TestCase):
|
class OfflineGenerationBlockSuperBaseCompressed(OfflineTestCaseMixin, TestCase):
|
||||||
template_names = ["base.html", "base2.html", "test_compressor_offline.html"]
|
template_names = ["base.html", "base2.html", "test_compressor_offline.html"]
|
||||||
templates_dir = 'test_block_super_base_compressed'
|
templates_dir = 'test_block_super_base_compressed'
|
||||||
|
Reference in New Issue
Block a user