Permalink
Browse files

Merge pull request #182 from dziegler/master

Offline compression with jinja2ext.py
  • Loading branch information...
Jannis Leidel
Jannis Leidel committed Jan 30, 2012
2 parents ab97095 + 3a3a4f8 commit 18ba062045e413604de36e72f56b1dceb7225b26
Showing with 91 additions and 101 deletions.
  1. +13 −50 compressor/contrib/jinja2ext.py
  2. +78 −51 compressor/templatetags/compress.py
@@ -1,27 +1,14 @@
-from django.core.exceptions import ImproperlyConfigured
-
from jinja2 import nodes
from jinja2.ext import Extension
from jinja2.exceptions import TemplateSyntaxError
-from compressor.conf import settings
-from compressor.utils import get_class
-from compressor.templatetags.compress import OUTPUT_FILE
-from compressor.cache import (cache_get, cache_set,
- get_templatetag_cachekey)
+from compressor.templatetags.compress import OUTPUT_FILE, CompressorMixin
-class CompressorExtension(Extension):
+class CompressorExtension(CompressorMixin, Extension):
tags = set(['compress'])
- @property
- def compressors(self):
- return {
- 'js': settings.COMPRESS_JS_COMPRESSOR,
- 'css': settings.COMPRESS_CSS_COMPRESSOR,
- }
-
def parse(self, parser):
lineno = parser.stream.next().lineno
kindarg = parser.parse_expression()
@@ -46,40 +33,16 @@ def parse(self, parser):
body).set_lineno(lineno)
def _compress(self, kind, mode, caller):
- mode = mode or OUTPUT_FILE
- Compressor = get_class(self.compressors.get(kind),
- exception=ImproperlyConfigured)
- original_content = caller()
- compressor = Compressor(original_content)
# This extension assumes that we won't force compression
forced = False
-
- # Prepare the actual compressor and check cache
- cache_key, cache_content = self.render_cached(kind, mode, compressor,
- forced)
- if cache_content is not None:
- return cache_content
-
- # call compressor output method and handle exceptions
- try:
- rendered_output = compressor.output(mode, forced)
- if cache_key:
- cache_set(cache_key, rendered_output)
- return rendered_output
- except Exception, e:
- if settings.DEBUG:
- raise e
-
- # Or don't do anything in production
- return original_content
-
- def render_cached(self, kind, mode, compressor, forced):
- """
- If enabled checks the cache for the given compressor's cache key
- 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_content = cache_get(cache_key)
- return cache_key, cache_content
- return None, None
+
+ mode = mode or OUTPUT_FILE
+ original_content = caller()
+ context = {
+ 'original_content': original_content
+ }
+ return self.render_compressed(context, kind, mode, forced=forced)
+
+ def get_original_content(self, context):
+ return context['original_content']
+
@@ -14,41 +14,39 @@
OUTPUT_MODES = (OUTPUT_FILE, OUTPUT_INLINE)
-class CompressorNode(template.Node):
-
- def __init__(self, nodelist, kind=None, mode=OUTPUT_FILE, name=None):
- self.nodelist = nodelist
- self.kind = kind
- self.mode = mode
- self.name = name
-
- def compressor_cls(self, *args, **kwargs):
- compressors = {
- "css": settings.COMPRESS_CSS_COMPRESSOR,
- "js": settings.COMPRESS_JS_COMPRESSOR,
+class CompressorMixin(object):
+
+ def get_original_content(self, context):
+ raise NotImplementedError
+
+ @property
+ def compressors(self):
+ return {
+ 'js': settings.COMPRESS_JS_COMPRESSOR,
+ 'css': settings.COMPRESS_CSS_COMPRESSOR,
}
- if self.kind not in compressors.keys():
+
+ def compressor_cls(self, kind, *args, **kwargs):
+ if kind not in self.compressors.keys():
raise template.TemplateSyntaxError(
"The compress tag's argument must be 'js' or 'css'.")
- return get_class(compressors.get(self.kind),
- exception=ImproperlyConfigured)(*args, **kwargs)
-
- 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_offline(self, context, forced):
+
+ return get_class(self.compressors.get(kind),
+ exception=ImproperlyConfigured)(*args, **kwargs)
+
+ def get_compressor(self, context, kind):
+ return self.compressor_cls(kind,
+ content=self.get_original_content(context),
+ context=context)
+
+ def render_offline(self, context, forced=False):
"""
If enabled and in offline mode, and not forced or in debug mode
check the offline cache and return the result if given
"""
if (settings.COMPRESS_ENABLED and
settings.COMPRESS_OFFLINE) and not forced:
- key = get_offline_hexdigest(self.nodelist.render(context))
+ key = get_offline_hexdigest(self.get_original_content(context))
offline_manifest = get_offline_manifest()
if key in offline_manifest:
return offline_manifest[key]
@@ -57,47 +55,76 @@ def render_offline(self, context, forced):
'enabled but key "%s" is missing from offline manifest. '
'You may need to run "python manage.py compress".' % key)
- def render_cached(self, compressor, forced):
+ def render_cached(self, compressor, kind, mode, forced=False):
"""
If enabled checks the cache for the given compressor's cache key
and return a tuple of cache key and output
"""
if settings.COMPRESS_ENABLED and not forced:
- cache_key = get_templatetag_cachekey(
- compressor, self.mode, self.kind)
+ cache_key = get_templatetag_cachekey(compressor, mode, kind)
cache_content = cache_get(cache_key)
return cache_key, cache_content
return None, None
-
- def render_output(self, compressor, forced=False):
- return compressor.output(self.mode, forced=forced)
-
- def render(self, context, forced=False):
-
- # Check if in debug mode
- if self.debug_mode(context):
- return self.nodelist.render(context)
-
+
+ def render_compressed(self, context, kind, mode, forced=False):
+
# See if it has been rendered offline
- cached_offline = self.render_offline(context, forced)
+ cached_offline = self.render_offline(context, forced=forced)
if cached_offline:
return cached_offline
-
- # Prepare the compressor
- context['compressed'] = {'name': self.name}
- compressor = self.compressor_cls(content=self.nodelist.render(context),
- context=context)
- # Check cache
- cache_key, cache_content = self.render_cached(compressor, forced)
+
+ context['compressed'] = {'name': getattr(self, 'name', None)}
+ compressor = self.get_compressor(context, kind)
+
+ # Prepare the actual compressor and check cache
+ cache_key, cache_content = self.render_cached(compressor, kind, mode, forced=forced)
if cache_content is not None:
return cache_content
# call compressor output method and handle exceptions
- rendered_output = self.render_output(compressor, forced)
- if cache_key:
- cache_set(cache_key, rendered_output)
- return rendered_output
+ try:
+ rendered_output = self.render_output(compressor, mode, forced=forced)
+ if cache_key:
+ cache_set(cache_key, rendered_output)
+ return rendered_output
+ except Exception, e:
+ if settings.DEBUG:
+ raise e
+
+ # Or don't do anything in production
+ return self.get_original_content(context)
+
+ def render_output(self, compressor, mode, forced=False):
+ return compressor.output(mode, forced=forced)
+
+
+class CompressorNode(CompressorMixin, template.Node):
+ def __init__(self, nodelist, kind=None, mode=OUTPUT_FILE, name=None):
+ self.nodelist = nodelist
+ self.kind = kind
+ self.mode = mode
+ self.name = name
+
+ def get_original_content(self, 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):
+
+ # Check if in debug mode
+ if self.debug_mode(context):
+ return self.get_original_content(context)
+
+ return self.render_compressed(context, self.kind, self.mode, forced=forced)
+
@register.tag
def compress(parser, token):

0 comments on commit 18ba062

Please sign in to comment.