From 3e6ee54ba8186bf485c417166f2dd9ff786fd3be Mon Sep 17 00:00:00 2001 From: dziegler Date: Fri, 16 Dec 2011 04:10:48 -0800 Subject: [PATCH 1/2] Allow jinja2ext to use offline compression. Refactor the compress templatetag and jinja2 extension to reduce code duplication --- compressor/contrib/jinja2ext.py | 55 +++---------- compressor/templatetags/compress.py | 122 +++++++++++++++++----------- 2 files changed, 86 insertions(+), 91 deletions(-) diff --git a/compressor/contrib/jinja2ext.py b/compressor/contrib/jinja2ext.py index 6ff6760..4067ffa 100644 --- a/compressor/contrib/jinja2ext.py +++ b/compressor/contrib/jinja2ext.py @@ -1,17 +1,12 @@ -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']) @@ -46,40 +41,16 @@ class CompressorExtension(Extension): 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'] + \ No newline at end of file diff --git a/compressor/templatetags/compress.py b/compressor/templatetags/compress.py index f1b1f01..dc7beb1 100644 --- a/compressor/templatetags/compress.py +++ b/compressor/templatetags/compress.py @@ -14,41 +14,36 @@ OUTPUT_INLINE = 'inline' 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): +class CompressorMixin(object): + + def get_original_content(self, context): + raise NotImplementedError + + def compressor_cls(self, kind, *args, **kwargs): compressors = { "css": settings.COMPRESS_CSS_COMPRESSOR, "js": settings.COMPRESS_JS_COMPRESSOR, } - if self.kind not in compressors.keys(): + if kind not in 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) + + return get_class(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 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): + 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 +52,76 @@ class CompressorNode(template.Node): '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, mode, kind, 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_compressed(self, context, mode, kind, forced=False): + + # See if it has been rendered offline + cached_offline = self.render_offline(context, forced=forced) + if cached_offline: + return cached_offline + + context['compressed'] = {'name': self.name} + compressor = self.get_compressor(context, self.kind) + + # Prepare the actual compressor and check cache + cache_key, cache_content = self.render_cached(compressor, mode, kind, forced=forced) + if cache_content is not None: + return cache_content - def render_output(self, compressor, forced=False): - return compressor.output(self.mode, forced=forced) + # call compressor output method and handle exceptions + 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.nodelist.render(context) - - # See if it has been rendered offline - cached_offline = self.render_offline(context, 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) - 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 - + return self.get_original_content(context) + + return self.render_compressed(context, self.mode, self.kind, forced) + @register.tag def compress(parser, token): From 3a3a4f8615af3a5ef7ea96c5fe540b6957b6088b Mon Sep 17 00:00:00 2001 From: dziegler Date: Fri, 16 Dec 2011 04:30:57 -0800 Subject: [PATCH 2/2] fix parameter ordering, tests pass --- compressor/contrib/jinja2ext.py | 8 -------- compressor/templatetags/compress.py | 27 +++++++++++++++------------ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/compressor/contrib/jinja2ext.py b/compressor/contrib/jinja2ext.py index 4067ffa..73af200 100644 --- a/compressor/contrib/jinja2ext.py +++ b/compressor/contrib/jinja2ext.py @@ -2,7 +2,6 @@ from jinja2 import nodes from jinja2.ext import Extension from jinja2.exceptions import TemplateSyntaxError -from compressor.conf import settings from compressor.templatetags.compress import OUTPUT_FILE, CompressorMixin @@ -10,13 +9,6 @@ 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() diff --git a/compressor/templatetags/compress.py b/compressor/templatetags/compress.py index dc7beb1..c35140b 100644 --- a/compressor/templatetags/compress.py +++ b/compressor/templatetags/compress.py @@ -19,16 +19,19 @@ class CompressorMixin(object): def get_original_content(self, context): raise NotImplementedError - def compressor_cls(self, kind, *args, **kwargs): - compressors = { - "css": settings.COMPRESS_CSS_COMPRESSOR, - "js": settings.COMPRESS_JS_COMPRESSOR, + @property + def compressors(self): + return { + 'js': settings.COMPRESS_JS_COMPRESSOR, + 'css': settings.COMPRESS_CSS_COMPRESSOR, } - if 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(kind), + return get_class(self.compressors.get(kind), exception=ImproperlyConfigured)(*args, **kwargs) def get_compressor(self, context, kind): @@ -52,7 +55,7 @@ class CompressorMixin(object): 'enabled but key "%s" is missing from offline manifest. ' 'You may need to run "python manage.py compress".' % key) - def render_cached(self, compressor, mode, kind, forced=False): + 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 @@ -63,18 +66,18 @@ class CompressorMixin(object): return cache_key, cache_content return None, None - def render_compressed(self, context, mode, kind, forced=False): + def render_compressed(self, context, kind, mode, forced=False): # See if it has been rendered offline cached_offline = self.render_offline(context, forced=forced) if cached_offline: return cached_offline - context['compressed'] = {'name': self.name} - compressor = self.get_compressor(context, self.kind) + 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, mode, kind, forced=forced) + cache_key, cache_content = self.render_cached(compressor, kind, mode, forced=forced) if cache_content is not None: return cache_content @@ -120,7 +123,7 @@ class CompressorNode(CompressorMixin, template.Node): if self.debug_mode(context): return self.get_original_content(context) - return self.render_compressed(context, self.mode, self.kind, forced) + return self.render_compressed(context, self.kind, self.mode, forced=forced) @register.tag