From 4b916124a228244696e93fcb366578d33972bac6 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Wed, 9 Feb 2011 04:51:36 +0100 Subject: [PATCH] Adopted AppSettings and moved a few things from utils to the cache module where they belong. --- compressor/base.py | 24 ++-- compressor/cache.py | 32 ++++- compressor/conf.py | 3 + compressor/conf/__init__.py | 0 compressor/conf/settings.py | 119 ----------------- compressor/css.py | 8 +- compressor/filters/__init__.py | 5 +- compressor/filters/closure.py | 4 +- compressor/filters/css_default.py | 8 +- compressor/filters/cssmin/__init__.py | 2 +- compressor/filters/csstidy.py | 2 +- compressor/filters/datauri.py | 9 +- compressor/filters/less.py | 4 +- compressor/filters/yui.py | 6 +- compressor/js.py | 6 +- compressor/management/commands/compress.py | 21 ++- compressor/management/commands/mtime_cache.py | 10 +- compressor/parser.py | 3 - compressor/settings.py | 125 ++++++++++++++++++ compressor/storage.py | 6 +- compressor/templatetags/compress.py | 13 +- compressor/tests/tests.py | 111 ++++++++-------- compressor/utils.py | 39 +----- 23 files changed, 279 insertions(+), 281 deletions(-) create mode 100644 compressor/conf.py delete mode 100644 compressor/conf/__init__.py delete mode 100644 compressor/conf/settings.py create mode 100644 compressor/settings.py diff --git a/compressor/base.py b/compressor/base.py index 8d1cfed..2d27c72 100644 --- a/compressor/base.py +++ b/compressor/base.py @@ -1,13 +1,13 @@ import os -from django.conf import settings as django_settings from django.template.loader import render_to_string from django.core.files.base import ContentFile -from compressor.conf import settings from compressor import filters +from compressor.cache import get_hexdigest, get_mtime +from compressor.conf import settings from compressor.exceptions import UncompressableFileError -from compressor.utils import get_hexdigest, get_mtime, get_class +from compressor.utils import get_class class Compressor(object): @@ -25,12 +25,12 @@ class Compressor(object): try: base_url = self.storage.base_url except AttributeError: - base_url = settings.URL + base_url = settings.COMPRESS_URL if not url.startswith(base_url): raise UncompressableFileError('"%s" is not in COMPRESS_URL ("%s") and can not be compressed' % (url, base_url)) basename = url.replace(base_url, "", 1) - filename = os.path.join(settings.ROOT, basename) + filename = os.path.join(settings.COMPRESS_ROOT, basename) if not os.path.exists(filename): raise UncompressableFileError('"%s" does not exist' % filename) return filename @@ -38,7 +38,7 @@ class Compressor(object): def _get_parser(self): if self._parser: return self._parser - parser_cls = get_class(settings.PARSER) + parser_cls = get_class(settings.COMPRESS_PARSER) self._parser = parser_cls(self.content) return self._parser @@ -54,7 +54,7 @@ class Compressor(object): def cachekey(self): cachebits = [self.content] cachebits.extend([str(m) for m in self.mtimes]) - cachestr = "".join(cachebits).encode(django_settings.DEFAULT_CHARSET) + cachestr = "".join(cachebits).encode(settings.DEFAULT_CHARSET) return "django_compressor.%s" % get_hexdigest(cachestr)[:12] @property @@ -82,7 +82,7 @@ class Compressor(object): input = fd.read() if self.filters: input = self.filter(input, 'input', filename=v, elem=elem) - charset = attribs.get('charset', django_settings.DEFAULT_CHARSET) + charset = attribs.get('charset', settings.DEFAULT_CHARSET) self._hunks.append(unicode(input, charset)) fd.close() return self._hunks @@ -91,7 +91,7 @@ class Compressor(object): # Design decision needed: either everything should be unicode up to # here or we encode strings as soon as we acquire them. Currently # concat() expects all hunks to be unicode and does the encoding - return "\n".join([hunk.encode(django_settings.DEFAULT_CHARSET) for hunk in self.hunks]) + return "\n".join([hunk.encode(settings.DEFAULT_CHARSET) for hunk in self.hunks]) def filter(self, content, method, **kwargs): for f in self.filters: @@ -121,7 +121,7 @@ class Compressor(object): def new_filepath(self): filename = "".join([self.hash, self.extension]) return os.path.join( - settings.OUTPUT_DIR.strip(os.sep), self.output_prefix, filename) + settings.COMPRESS_OUTPUT_DIR.strip(os.sep), self.output_prefix, filename) def save_file(self): if self.storage.exists(self.new_filepath): @@ -130,7 +130,7 @@ class Compressor(object): return True def output(self): - if not settings.ENABLED: + if not settings.COMPRESS_ENABLED: return self.content self.save_file() context = getattr(self, 'extra_context', {}) @@ -138,7 +138,7 @@ class Compressor(object): return render_to_string(self.template_name, context) def output_inline(self): - context = {'content': settings.ENABLED and self.combined or self.concat()} + context = {'content': settings.COMPRESS_ENABLED and self.combined or self.concat()} if hasattr(self, 'extra_context'): context.update(self.extra_context) return render_to_string(self.template_name_inline, context) diff --git a/compressor/cache.py b/compressor/cache.py index 1b53393..cee985b 100644 --- a/compressor/cache.py +++ b/compressor/cache.py @@ -1,5 +1,35 @@ +import os + from django.core.cache import get_cache +from django.utils.encoding import smart_str +from django.utils.hashcompat import sha_constructor from compressor.conf import settings -cache = get_cache(settings.CACHE_BACKEND) +def get_hexdigest(plaintext): + return sha_constructor(plaintext).hexdigest() + +def get_mtime_cachekey(filename): + return "django_compressor.mtime.%s" % filename + +def get_offline_cachekey(source): + return ("django_compressor.offline.%s" + % get_hexdigest("".join(smart_str(s) for s in source))) + +def get_mtime(filename): + if settings.COMPRESS_MTIME_DELAY: + key = get_mtime_cachekey(filename) + mtime = cache.get(key) + if mtime is None: + mtime = os.path.getmtime(filename) + cache.set(key, mtime, settings.COMPRESS_MTIME_DELAY) + return mtime + return os.path.getmtime(filename) + +def get_hashed_mtime(filename, length=12): + filename = os.path.realpath(filename) + mtime = str(int(get_mtime(filename))) + return get_hexdigest(mtime)[:length] + + +cache = get_cache(settings.COMPRESS_CACHE_BACKEND) diff --git a/compressor/conf.py b/compressor/conf.py new file mode 100644 index 0000000..e4e2a81 --- /dev/null +++ b/compressor/conf.py @@ -0,0 +1,3 @@ +from compressor.settings import CompressorSettings + +settings = CompressorSettings(prefix="COMPRESS") diff --git a/compressor/conf/__init__.py b/compressor/conf/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/compressor/conf/settings.py b/compressor/conf/settings.py deleted file mode 100644 index 392a3de..0000000 --- a/compressor/conf/settings.py +++ /dev/null @@ -1,119 +0,0 @@ -import os -from django.conf import settings -from django.core.exceptions import ImproperlyConfigured - -# Main switch -ENABLED = getattr(settings, 'COMPRESS', not settings.DEBUG) - -# Uses the 1.3 STATIC_URL setting by default -URL = getattr(settings, 'COMPRESS_URL', getattr(settings, 'STATIC_URL', None)) -# Check for emptyness since STATIC_URL can be None and '' -if URL: - # Then on to extensive testing - ROOT = getattr(settings, 'COMPRESS_ROOT', getattr(settings, 'STATIC_ROOT', None)) - if not ROOT: - raise ImproperlyConfigured('The COMPRESS_ROOT setting (or its ' - 'fallback STATIC_ROOT) must be set.') - # In case staticfiles is used, make sure COMPRESS_URL can be used - # by checking if the the FileSystemFinder is installed, and if is - # checking if COMPRESS_ROOT is in STATICFILES_DIRS to allow finding - # compressed files. - if ("staticfiles" in settings.INSTALLED_APPS or - "django.contrib.staticfiles" in settings.INSTALLED_APPS): - try: - from staticfiles.settings import FINDERS as finders - except ImportError: - finders = [] - if not finders: - finders = getattr(settings, 'STATICFILES_FINDERS', []) - if ("django.contrib.staticfiles.finders.FileSystemFinder" not in finders and - "staticfiles.finders.FileSystemFinder" not in finders): - raise ImproperlyConfigured('Please enable the FileSystemFinder ' - 'finder of the staticfiles app to ' - 'use it with django_compressor.') - abs_paths = [] - for path in getattr(settings, 'STATICFILES_DIRS', []): - if isinstance(path, tuple) or isinstance(path, list): # stupid Python 2.4 - path = path[1] # in case the STATICFILES_DIRS setting has a prefix - abs_paths.append(os.path.abspath(path)) - if os.path.abspath(ROOT) not in abs_paths: - raise ImproperlyConfigured('Please add COMPRESS_ROOT to the ' - 'STATICFILES_DIRS setting when using the ' - 'staticfiles app.') -else: - # Fallback to good ol' time of double meaning - URL, ROOT = settings.MEDIA_URL, settings.MEDIA_ROOT - -if not URL.endswith('/'): - raise ImproperlyConfigured('The URL settings (e.g. COMPRESS_URL) ' - 'must have a trailing slash.') - -OUTPUT_DIR = getattr(settings, 'COMPRESS_OUTPUT_DIR', 'cache') -STORAGE = getattr(settings, 'COMPRESS_STORAGE', 'compressor.storage.CompressorFileStorage') - -CSS_FILTERS = getattr(settings, 'COMPRESS_CSS_FILTERS', ['compressor.filters.css_default.CssAbsoluteFilter']) -JS_FILTERS = getattr(settings, 'COMPRESS_JS_FILTERS', ['compressor.filters.jsmin.JSMinFilter']) - -if CSS_FILTERS is None: - CSS_FILTERS = [] - -if JS_FILTERS is None: - JS_FILTERS = [] - -LESSC_BINARY = LESSC_BINARY = getattr(settings, 'COMPRESS_LESSC_BINARY', 'lessc') - -CLOSURE_COMPILER_BINARY = getattr(settings, 'COMPRESS_CLOSURE_COMPILER_BINARY', 'java -jar compiler.jar') -CLOSURE_COMPILER_ARGUMENTS = getattr(settings, 'COMPRESS_CLOSURE_COMPILER_ARGUMENTS', '') - -CSSTIDY_BINARY = getattr(settings, 'CSSTIDY_BINARY', - getattr(settings, 'COMPRESS_CSSTIDY_BINARY', 'csstidy')) -CSSTIDY_ARGUMENTS = getattr(settings, 'CSSTIDY_ARGUMENTS', - getattr(settings, 'COMPRESS_CSSTIDY_ARGUMENTS', '--template=highest')) - -YUI_BINARY = getattr(settings, 'COMPRESS_YUI_BINARY', 'java -jar yuicompressor.jar') -YUI_CSS_ARGUMENTS = getattr(settings, 'COMPRESS_YUI_CSS_ARGUMENTS', '') -YUI_JS_ARGUMENTS = getattr(settings, 'COMPRESS_YUI_JS_ARGUMENTS', '') - -DATA_URI_MIN_SIZE = getattr(settings, 'COMPRESS_DATA_URI_MIN_SIZE', 1024) - -# rebuilds the cache every 30 days if nothing has changed. -REBUILD_TIMEOUT = getattr(settings, 'COMPRESS_REBUILD_TIMEOUT', 60 * 60 * 24 * 30) # 30 days - -# the upper bound on how long any compression should take to be generated -# (used against dog piling, should be a lot smaller than REBUILD_TIMEOUT -MINT_DELAY = getattr(settings, 'COMPRESS_MINT_DELAY', 30) # 30 seconds - -# check for file changes only after a delay (in seconds, disabled by default) -MTIME_DELAY = getattr(settings, 'COMPRESS_MTIME_DELAY', None) - -# the backend to use when parsing the JavaScript or Stylesheet files -PARSER = getattr(settings, 'COMPRESS_PARSER', 'compressor.parser.BeautifulSoupParser') - -# Allows changing verbosity from the settings. -VERBOSE = getattr(settings, "COMPRESS_VERBOSE", False) - -# the cache backend to use -CACHE_BACKEND = getattr(settings, 'COMPRESS_CACHE_BACKEND', None) -if CACHE_BACKEND is None: - # If we are on Django 1.3 AND using the new CACHES setting... - if getattr(settings, "CACHES", None): - CACHE_BACKEND = "default" - else: - # fallback for people still using the old CACHE_BACKEND setting - CACHE_BACKEND = settings.CACHE_BACKEND - -# enables the offline cache -- a cache that is filled by the compress management command -OFFLINE = getattr(settings, 'COMPRESS_OFFLINE', False) - -# invalidates the offline cache after one year -OFFLINE_TIMEOUT = getattr(settings, 'COMPRESS_OFFLINE_TIMEOUT', 60 * 60 * 24 * 365) # 1 year - -# The context to be used when compressing the files "offline" -OFFLINE_CONTEXT = getattr(settings, 'COMPRESS_OFFLINE_CONTEXT', {}) -if not OFFLINE_CONTEXT: - OFFLINE_CONTEXT = { - 'MEDIA_URL': settings.MEDIA_URL, - } - # Adds the 1.3 STATIC_URL setting to the context if available - if getattr(settings, 'STATIC_URL', None): - OFFLINE_CONTEXT['STATIC_URL'] = settings.STATIC_URL diff --git a/compressor/css.py b/compressor/css.py index 79acb87..2c8b7b9 100644 --- a/compressor/css.py +++ b/compressor/css.py @@ -1,5 +1,3 @@ -from django.conf import settings as django_settings - from compressor.conf import settings from compressor.base import Compressor from compressor.exceptions import UncompressableFileError @@ -11,7 +9,7 @@ class CssCompressor(Compressor): self.extension = ".css" self.template_name = "compressor/css.html" self.template_name_inline = "compressor/css_inline.html" - self.filters = list(settings.CSS_FILTERS) + self.filters = list(settings.COMPRESS_CSS_FILTERS) self.type = 'css' def split_contents(self): @@ -27,7 +25,7 @@ class CssCompressor(Compressor): content = self.parser.elem_content(elem) data = ('file', self.get_filename(elem_attribs['href']), elem) except UncompressableFileError: - if django_settings.DEBUG: + if settings.DEBUG: raise elif elem_name == 'style': data = ('hunk', self.parser.elem_content(elem), elem) @@ -48,7 +46,7 @@ class CssCompressor(Compressor): self.split_contents() if not hasattr(self, 'media_nodes'): return super(CssCompressor, self).output() - if not settings.ENABLED: + if not settings.COMPRESS_ENABLED: return self.content ret = [] for media, subnode in self.media_nodes: diff --git a/compressor/filters/__init__.py b/compressor/filters/__init__.py index adc7c69..4526faa 100644 --- a/compressor/filters/__init__.py +++ b/compressor/filters/__init__.py @@ -1,12 +1,11 @@ -from compressor.exceptions import FilterError -from compressor.utils import get_class, get_mod_func from compressor.conf import settings +from compressor.exceptions import FilterError class FilterBase(object): def __init__(self, content, filter_type=None, verbose=0): self.type = filter_type self.content = content - self.verbose = verbose or settings.VERBOSE + self.verbose = verbose or settings.COMPRESS_VERBOSE def input(self, **kwargs): raise NotImplementedError diff --git a/compressor/filters/closure.py b/compressor/filters/closure.py index a016fed..878e197 100644 --- a/compressor/filters/closure.py +++ b/compressor/filters/closure.py @@ -8,9 +8,9 @@ from compressor.utils import cmd_split class ClosureCompilerFilter(FilterBase): def output(self, **kwargs): - arguments = settings.CLOSURE_COMPILER_ARGUMENTS + arguments = settings.COMPRESS_CLOSURE_COMPILER_ARGUMENTS - command = '%s %s' % (settings.CLOSURE_COMPILER_BINARY, arguments) + command = '%s %s' % (settings.COMPRESS_CLOSURE_COMPILER_BINARY, arguments) try: p = Popen(cmd_split(command), stdout=PIPE, stdin=PIPE, stderr=PIPE) diff --git a/compressor/filters/css_default.py b/compressor/filters/css_default.py index 666af47..35a60dd 100644 --- a/compressor/filters/css_default.py +++ b/compressor/filters/css_default.py @@ -2,23 +2,23 @@ import os import re import posixpath -from compressor.filters import FilterBase, FilterError +from compressor.cache import get_hexdigest, get_mtime from compressor.conf import settings -from compressor.utils import get_hexdigest, get_mtime +from compressor.filters import FilterBase URL_PATTERN = re.compile(r'url\(([^\)]+)\)') class CssAbsoluteFilter(FilterBase): def input(self, filename=None, **kwargs): - media_root = os.path.normcase(os.path.abspath(settings.ROOT)) + media_root = os.path.normcase(os.path.abspath(settings.COMPRESS_ROOT)) if filename is not None: filename = os.path.normcase(os.path.abspath(filename)) if not filename or not filename.startswith(media_root): return self.content self.media_path = filename[len(media_root):].replace(os.sep, '/') self.media_path = self.media_path.lstrip('/') - self.media_url = settings.URL.rstrip('/') + self.media_url = settings.COMPRESS_URL.rstrip('/') try: mtime = get_mtime(filename) self.mtime = get_hexdigest(str(int(mtime)))[:12] diff --git a/compressor/filters/cssmin/__init__.py b/compressor/filters/cssmin/__init__.py index 4c4c6f5..9fc1f85 100644 --- a/compressor/filters/cssmin/__init__.py +++ b/compressor/filters/cssmin/__init__.py @@ -1,4 +1,4 @@ -from compressor.filters import FilterBase, FilterError +from compressor.filters import FilterBase from compressor.filters.cssmin.cssmin import cssmin class CSSMinFilter(FilterBase): diff --git a/compressor/filters/csstidy.py b/compressor/filters/csstidy.py index 93aa190..c0600ab 100644 --- a/compressor/filters/csstidy.py +++ b/compressor/filters/csstidy.py @@ -16,7 +16,7 @@ class CSSTidyFilter(FilterBase): output_file = tempfile.NamedTemporaryFile(mode='w+b') - command = '%s %s %s %s' % (settings.CSSTIDY_BINARY, tmp_file.name, settings.CSSTIDY_ARGUMENTS, output_file.name) + command = '%s %s %s %s' % (settings.COMPRESS_CSSTIDY_BINARY, tmp_file.name, settings.COMPRESS_CSSTIDY_ARGUMENTS, output_file.name) command_output = Popen(command, shell=True, stdout=PIPE, stdin=PIPE, stderr=PIPE).communicate() diff --git a/compressor/filters/datauri.py b/compressor/filters/datauri.py index b252135..a72cb57 100644 --- a/compressor/filters/datauri.py +++ b/compressor/filters/datauri.py @@ -1,11 +1,10 @@ import os import re import mimetypes -import urlparse from base64 import b64encode -from compressor.filters import FilterBase from compressor.conf import settings +from compressor.filters import FilterBase class DataUriFilter(FilterBase): """Filter for embedding media as data: URIs. @@ -18,7 +17,7 @@ class DataUriFilter(FilterBase): Don't use this class directly. Use a subclass. """ def input(self, filename=None, **kwargs): - if not filename or not filename.startswith(settings.ROOT): + if not filename or not filename.startswith(settings.COMPRESS_ROOT): return self.content output = self.content for url_pattern in self.url_patterns: @@ -29,13 +28,13 @@ class DataUriFilter(FilterBase): # strip query string of file paths if "?" in url: url = url.split("?")[0] - return os.path.join(settings.ROOT, url[len(settings.URL):]) + return os.path.join(settings.COMPRESS_ROOT, url[len(settings.COMPRESS_URL):]) def data_uri_converter(self, matchobj): url = matchobj.group(1).strip(' \'"') if not url.startswith('data:'): path = self.get_file_path(url) - if os.stat(path).st_size <= settings.DATA_URI_MIN_SIZE: + if os.stat(path).st_size <= settings.COMPRESS_DATA_URI_MIN_SIZE: data = b64encode(open(path, 'rb').read()) return 'url("data:%s;base64,%s")' % (mimetypes.guess_type(path)[0], data) return 'url("%s")' % url diff --git a/compressor/filters/less.py b/compressor/filters/less.py index c68aa21..7c75f6f 100644 --- a/compressor/filters/less.py +++ b/compressor/filters/less.py @@ -3,7 +3,7 @@ import warnings import tempfile from compressor.conf import settings -from compressor.filters import FilterBase, FilterError +from compressor.filters import FilterBase warnings.simplefilter('ignore', RuntimeWarning) @@ -17,7 +17,7 @@ class LessFilter(FilterBase): output_file = tempfile.NamedTemporaryFile(mode='w+b') - command = '%s %s %s' % (settings.LESSC_BINARY, tmp_file.name, output_file.name) + command = '%s %s %s' % (settings.COMPRESS_LESSC_BINARY, tmp_file.name, output_file.name) command_output = os.popen(command).read() diff --git a/compressor/filters/yui.py b/compressor/filters/yui.py index 0109b81..5574fcb 100644 --- a/compressor/filters/yui.py +++ b/compressor/filters/yui.py @@ -10,11 +10,11 @@ class YUICompressorFilter(FilterBase): def output(self, **kwargs): arguments = '' if self.type == 'js': - arguments = settings.YUI_JS_ARGUMENTS + arguments = settings.COMPRESS_YUI_JS_ARGUMENTS if self.type == 'css': - arguments = settings.YUI_CSS_ARGUMENTS + arguments = settings.COMPRESS_YUI_CSS_ARGUMENTS - command = '%s --type=%s %s' % (settings.YUI_BINARY, self.type, arguments) + command = '%s --type=%s %s' % (settings.COMPRESS_YUI_BINARY, self.type, arguments) if self.verbose: command += ' --verbose' diff --git a/compressor/js.py b/compressor/js.py index ef5af72..f95d373 100644 --- a/compressor/js.py +++ b/compressor/js.py @@ -1,5 +1,3 @@ -from django.conf import settings as django_settings - from compressor.conf import settings from compressor.base import Compressor from compressor.exceptions import UncompressableFileError @@ -12,7 +10,7 @@ class JsCompressor(Compressor): self.extension = ".js" self.template_name = "compressor/js.html" self.template_name_inline = "compressor/js_inline.html" - self.filters = settings.JS_FILTERS + self.filters = settings.COMPRESS_JS_FILTERS self.type = 'js' def split_contents(self): @@ -24,7 +22,7 @@ class JsCompressor(Compressor): try: self.split_content.append(('file', self.get_filename(attribs['src']), elem)) except UncompressableFileError: - if django_settings.DEBUG: + if settings.DEBUG: raise else: content = self.parser.elem_content(elem) diff --git a/compressor/management/commands/compress.py b/compressor/management/commands/compress.py index 66e62d3..d1d2452 100644 --- a/compressor/management/commands/compress.py +++ b/compressor/management/commands/compress.py @@ -9,16 +9,15 @@ try: except ImportError: from StringIO import StringIO -from django.conf import settings as django_settings from django.core.management.base import NoArgsCommand, CommandError from django.template import Context, Template, TemplateDoesNotExist, TemplateSyntaxError from django.utils.datastructures import SortedDict -from compressor.cache import cache +from compressor.cache import cache, get_offline_cachekey from compressor.conf import settings from compressor.exceptions import OfflineGenerationError from compressor.templatetags.compress import CompressorNode -from compressor.utils import get_offline_cachekey, walk, any, import_module +from compressor.utils import walk, any, import_module class Command(NoArgsCommand): @@ -46,7 +45,7 @@ class Command(NoArgsCommand): from django.template.loader import find_template_source as finder_func try: source, name = finder_func('test') - except TemplateDoesNotExist, e: + except TemplateDoesNotExist: pass from django.template.loader import template_source_loaders return template_source_loaders or [] @@ -64,7 +63,7 @@ class Command(NoArgsCommand): verbosity = int(options.get("verbosity", 0)) if not log: log = StringIO() - if not django_settings.TEMPLATE_LOADERS: + if not settings.TEMPLATE_LOADERS: raise OfflineGenerationError("No template loaders defined. You " "must set TEMPLATE_LOADERS in your " "settings.") @@ -76,7 +75,7 @@ class Command(NoArgsCommand): if get_template_sources is None: get_template_sources = loader.get_template_sources paths.update(list(get_template_sources(''))) - except (ImportError, AttributeError), e: + except (ImportError, AttributeError): # Yeah, this didn't work out so well, let's move on pass if not paths: @@ -107,7 +106,7 @@ class Command(NoArgsCommand): template_file = open(template_name) try: template = Template(template_file.read().decode( - django_settings.FILE_CHARSET)) + settings.FILE_CHARSET)) finally: template_file.close() except IOError: # unreadable file -> ignore @@ -136,12 +135,12 @@ class Command(NoArgsCommand): log.write("Compressing... ") count = 0 results = [] - context = Context(settings.OFFLINE_CONTEXT) + context = Context(settings.COMPRESS_OFFLINE_CONTEXT) for nodes in compressor_nodes.values(): for node in nodes: key = get_offline_cachekey(node.nodelist) result = node.render(context, compress=True, offline=False) - cache.set(key, result, settings.OFFLINE_TIMEOUT) + cache.set(key, result, settings.COMPRESS_OFFLINE_TIMEOUT) results.append(result) count += 1 log.write("done\nCompressed %d block(s) from %d template(s).\n" @@ -183,11 +182,11 @@ class Command(NoArgsCommand): return set([x for x in ext_list if x != '.py']) def handle_noargs(self, **options): - if not settings.ENABLED and not options.get("force"): + if not settings.COMPRESS_ENABLED and not options.get("force"): raise CommandError("Compressor is disabled. Set COMPRESS " "settting to True to enable it " "(Use -f/--force to override).") - if not settings.OFFLINE: + if not settings.COMPRESS_OFFLINE: if not options.get("force"): raise CommandError("Aborting; COMPRESS_OFFLINE is not set. " "(Use -f/--force to override)") diff --git a/compressor/management/commands/mtime_cache.py b/compressor/management/commands/mtime_cache.py index ecadc08..8dd0b95 100644 --- a/compressor/management/commands/mtime_cache.py +++ b/compressor/management/commands/mtime_cache.py @@ -4,9 +4,9 @@ from optparse import make_option from django.core.management.base import NoArgsCommand, CommandError -from compressor.cache import cache +from compressor.cache import cache, get_mtime, get_mtime_cachekey from compressor.conf import settings -from compressor.utils import get_mtime, get_mtime_cachekey, walk +from compressor.utils import walk class Command(NoArgsCommand): help = "Add or remove all mtime values from the cache" @@ -50,19 +50,19 @@ class Command(NoArgsCommand): if (options['add'] and options['clean']) or (not options['add'] and not options['clean']): raise CommandError('Please specify either "--add" or "--clean"') - if not settings.MTIME_DELAY: + if not settings.COMPRESS_MTIME_DELAY: raise CommandError('mtime caching is currently disabled. Please ' 'set the COMPRESS_MTIME_DELAY setting to a number of seconds.') files_to_add = set() keys_to_delete = set() - for root, dirs, files in walk(settings.ROOT, followlinks=options['follow_links']): + for root, dirs, files in walk(settings.COMPRESS_ROOT, followlinks=options['follow_links']): for dir_ in dirs: if self.is_ignored(dir_): dirs.remove(dir_) for filename in files: - common = "".join(root.split(settings.ROOT)) + common = "".join(root.split(settings.COMPRESS_ROOT)) if common.startswith(os.sep): common = common[len(os.sep):] if self.is_ignored(os.path.join(common, filename)): diff --git a/compressor/parser.py b/compressor/parser.py index 01cf5ca..2052e5a 100644 --- a/compressor/parser.py +++ b/compressor/parser.py @@ -1,9 +1,6 @@ -from django.conf import settings as django_settings from django.utils.encoding import smart_unicode -from compressor.conf import settings from compressor.exceptions import ParserError -from compressor.utils import get_class class ParserBase(object): diff --git a/compressor/settings.py b/compressor/settings.py new file mode 100644 index 0000000..15374ac --- /dev/null +++ b/compressor/settings.py @@ -0,0 +1,125 @@ +import os + +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured + +from compressor.utils import AppSettings + +class CompressorSettings(AppSettings): + # Main switch + ENABLED = False + # Allows changing verbosity from the settings. + VERBOSE = False + # the backend to use when parsing the JavaScript or Stylesheet files + PARSER = 'compressor.parser.BeautifulSoupParser' + OUTPUT_DIR = 'cache' + STORAGE = 'compressor.storage.CompressorFileStorage' + + URL = None + ROOT = None + + CSS_FILTERS = ['compressor.filters.css_default.CssAbsoluteFilter'] + JS_FILTERS = ['compressor.filters.jsmin.JSMinFilter'] + + LESSC_BINARY = LESSC_BINARY = 'lessc' + CLOSURE_COMPILER_BINARY = 'java -jar compiler.jar' + CLOSURE_COMPILER_ARGUMENTS = '' + CSSTIDY_BINARY = 'csstidy' + CSSTIDY_ARGUMENTS = '--template=highest' + YUI_BINARY = 'java -jar yuicompressor.jar' + YUI_CSS_ARGUMENTS = '' + YUI_JS_ARGUMENTS = 'COMPRESS_YUI_JS_ARGUMENTS' + + DATA_URI_MIN_SIZE = 1024 + + # the cache backend to use + CACHE_BACKEND = None + # rebuilds the cache every 30 days if nothing has changed. + REBUILD_TIMEOUT = 60 * 60 * 24 * 30 # 30 days + # the upper bound on how long any compression should take to be generated + # (used against dog piling, should be a lot smaller than REBUILD_TIMEOUT + MINT_DELAY = 30 # 30 seconds + # check for file changes only after a delay (in seconds, disabled by default) + MTIME_DELAY = None + + # enables the offline cache -- a cache that is filled by the compress management command + OFFLINE = False + # invalidates the offline cache after one year + OFFLINE_TIMEOUT = 60 * 60 * 24 * 365 # 1 year + # The context to be used when compressing the files "offline" + OFFLINE_CONTEXT = {} + + def configure_enabled(self, value): + return value or getattr(settings, 'COMPRESS', not self.DEBUG) + + def configure_url(self, value): + # Uses the 1.3 STATIC_URL setting by default + url = getattr(settings, 'STATIC_URL', value) + # Check for emptyness since STATIC_URL can be None and '' + if url: + # Then on to extensive testing + root = getattr(settings, 'STATIC_ROOT', None) + if not root: + raise ImproperlyConfigured('The COMPRESS_ROOT setting (or its ' + 'fallback STATIC_ROOT) must be set.') + # In case staticfiles is used, make sure COMPRESS_URL can be used + # by checking if the the FileSystemFinder is installed, and if is + # checking if COMPRESS_ROOT is in STATICFILES_DIRS to allow finding + # compressed files. + if ("staticfiles" in self.INSTALLED_APPS or + "django.contrib.staticfiles" in self.INSTALLED_APPS): + try: + from staticfiles.conf import settings as staticfiles_settings + finders = staticfiles_settings.STATICFILES_FINDERS + standalone = True + except ImportError: + finders = [] + standalone = False + if not finders: + finders = getattr(settings, 'STATICFILES_FINDERS', []) + if ("django.contrib.staticfiles.finders.FileSystemFinder" not in finders and + "staticfiles.finders.FileSystemFinder" not in finders): + raise ImproperlyConfigured( + 'Please enable the FileSystemFinder finder of the ' + 'staticfiles app to use it with django_compressor.') + abs_paths = [] + output_path = os.path.join(root, self.COMPRESS_OUTPUT_DIR) + for path in getattr(settings, 'STATICFILES_DIRS', []): + if isinstance(path, tuple) or isinstance(path, list): # stupid Python 2.4 + path = path[1] # in case the STATICFILES_DIRS setting has a prefix + abs_paths.append(os.path.abspath(path)) + if os.path.abspath(output_path) not in abs_paths: + extension = ((self.COMPRESS_OUTPUT_DIR, output_path),) + if standalone: + from staticfiles.conf import settings as staticfiles_settings + staticfiles_settings.STATICFILES_DIRS += extension + else: + settings.STATICFILES_DIRS += extension + else: + # Fallback to good ol' times of ambiguity + url, root = settings.MEDIA_URL, settings.MEDIA_ROOT + + if not url.endswith('/'): + raise ImproperlyConfigured('The URL settings (e.g. COMPRESS_URL) ' + 'must have a trailing slash.') + self.COMPRESS_ROOT = root + return url + + def configure_cache_backend(self, value): + if value is None: + # If we are on Django 1.3 AND using the new CACHES setting... + if getattr(settings, "CACHES", None): + return "default" + # fallback for people still using the old CACHE_BACKEND setting + return settings.CACHE_BACKEND + return value + + def configure_offline_context(self, value): + if value: + value = { + 'MEDIA_URL': settings.MEDIA_URL, + } + # Adds the 1.3 STATIC_URL setting to the context if available + if getattr(settings, 'STATIC_URL', None): + value['STATIC_URL'] = settings.STATIC_URL + return value diff --git a/compressor/storage.py b/compressor/storage.py index 729afbd..6492a3a 100644 --- a/compressor/storage.py +++ b/compressor/storage.py @@ -13,14 +13,14 @@ class CompressorFileStorage(FileSystemStorage): """ def __init__(self, location=None, base_url=None, *args, **kwargs): if location is None: - location = settings.ROOT + location = settings.COMPRESS_ROOT if base_url is None: - base_url = settings.URL + base_url = settings.COMPRESS_URL super(CompressorFileStorage, self).__init__(location, base_url, *args, **kwargs) class DefaultStorage(LazyObject): def _setup(self): - self._wrapped = get_storage_class(settings.STORAGE)() + self._wrapped = get_storage_class(settings.COMPRESS_STORAGE)() default_storage = DefaultStorage() diff --git a/compressor/templatetags/compress.py b/compressor/templatetags/compress.py index 4320de8..47ff41a 100644 --- a/compressor/templatetags/compress.py +++ b/compressor/templatetags/compress.py @@ -2,11 +2,10 @@ import time from django import template +from compressor.cache import cache, get_offline_cachekey +from compressor.conf import settings from compressor.css import CssCompressor from compressor.js import JsCompressor -from compressor.cache import cache -from compressor.conf import settings -from compressor.utils import get_offline_cachekey OUTPUT_FILE = 'file' @@ -28,17 +27,17 @@ class CompressorNode(template.Node): if (time.time() > refresh_time) and not refreshed: # Store the stale value while the cache # revalidates for another MINT_DELAY seconds. - self.cache_set(key, val, timeout=settings.MINT_DELAY, refreshed=True) + self.cache_set(key, val, timeout=settings.COMPRESS_MINT_DELAY, refreshed=True) return None return val - def cache_set(self, key, val, timeout=settings.REBUILD_TIMEOUT, refreshed=False): + def cache_set(self, key, val, timeout=settings.COMPRESS_REBUILD_TIMEOUT, refreshed=False): refresh_time = timeout + time.time() - real_timeout = timeout + settings.MINT_DELAY + real_timeout = timeout + settings.COMPRESS_MINT_DELAY packed_val = (val, refresh_time, refreshed) return cache.set(key, packed_val, real_timeout) - def render(self, context, compress=settings.ENABLED, offline=settings.OFFLINE): + def render(self, context, compress=settings.COMPRESS_ENABLED, offline=settings.COMPRESS_OFFLINE): if compress and offline: key = get_offline_cachekey(self.nodelist) content = cache.get(key) diff --git a/compressor/tests/tests.py b/compressor/tests/tests.py index e59caf9..04e2be2 100644 --- a/compressor/tests/tests.py +++ b/compressor/tests/tests.py @@ -2,24 +2,23 @@ import os import re from BeautifulSoup import BeautifulSoup -from django.conf import settings as django_settings from django.core.cache.backends import dummy from django.core.files.storage import get_storage_class from django.template import Template, Context, TemplateSyntaxError from django.test import TestCase from compressor import storage +from compressor.cache import get_hashed_mtime from compressor.conf import settings from compressor.css import CssCompressor from compressor.js import JsCompressor from compressor.management.commands.compress import Command as CompressCommand -from compressor.utils import get_hashed_mtime class CompressorTestCase(TestCase): def setUp(self): - settings.ENABLED = True + settings.COMPRESS_ENABLED = True self.css = """ @@ -35,9 +34,9 @@ class CompressorTestCase(TestCase): def test_css_split(self): out = [ - ('file', os.path.join(settings.ROOT, u'css/one.css'), u''), + ('file', os.path.join(settings.COMPRESS_ROOT, u'css/one.css'), u''), ('hunk', u'p { border:5px solid green;}', u''), - ('file', os.path.join(settings.ROOT, u'css/two.css'), u''), + ('file', os.path.join(settings.COMPRESS_ROOT, u'css/two.css'), u''), ] split = self.cssNode.split_contents() split = [(x[0], x[1], self.cssNode.parser.elem_str(x[2])) for x in split] @@ -57,7 +56,7 @@ class CompressorTestCase(TestCase): self.assert_(is_date.match(str(float(date))), "mtimes is returning something that doesn't look like a date: %s" % date) def test_css_return_if_off(self): - settings.ENABLED = False + settings.COMPRESS_ENABLED = False self.assertEqual(self.css, self.cssNode.output()) def test_cachekey(self): @@ -72,7 +71,7 @@ class CompressorTestCase(TestCase): self.assertEqual(output, self.cssNode.output().strip()) def test_js_split(self): - out = [('file', os.path.join(settings.ROOT, u'js/one.js'), ''), + out = [('file', os.path.join(settings.COMPRESS_ROOT, u'js/one.js'), ''), ('hunk', u'obj.value = "value";', '') ] split = self.jsNode.split_contents() @@ -92,7 +91,7 @@ class CompressorTestCase(TestCase): self.assertEqual(out, self.jsNode.combined) def test_js_return_if_off(self): - settings.ENABLED = False + settings.COMPRESS_ENABLED = False self.assertEqual(self.js, self.jsNode.output()) def test_js_return_if_on(self): @@ -100,17 +99,17 @@ class CompressorTestCase(TestCase): self.assertEqual(output, self.jsNode.output()) def test_custom_output_dir(self): - old_output_dir = settings.OUTPUT_DIR - settings.OUTPUT_DIR = 'custom' + old_output_dir = settings.COMPRESS_OUTPUT_DIR + settings.COMPRESS_OUTPUT_DIR = 'custom' output = u'' self.assertEqual(output, JsCompressor(self.js).output()) - settings.OUTPUT_DIR = '' + settings.COMPRESS_OUTPUT_DIR = '' output = u'' self.assertEqual(output, JsCompressor(self.js).output()) - settings.OUTPUT_DIR = '/custom/nested/' + settings.COMPRESS_OUTPUT_DIR = '/custom/nested/' output = u'' self.assertEqual(output, JsCompressor(self.js).output()) - settings.OUTPUT_DIR = old_output_dir + settings.COMPRESS_OUTPUT_DIR = old_output_dir try: @@ -123,27 +122,27 @@ else: def test_css_split(self): out = [ - ('file', os.path.join(settings.ROOT, u'css/one.css'), u''), + ('file', os.path.join(settings.COMPRESS_ROOT, u'css/one.css'), u''), ('hunk', u'p { border:5px solid green;}', u''), - ('file', os.path.join(settings.ROOT, u'css/two.css'), u''), + ('file', os.path.join(settings.COMPRESS_ROOT, u'css/two.css'), u''), ] split = self.cssNode.split_contents() split = [(x[0], x[1], self.cssNode.parser.elem_str(x[2])) for x in split] self.assertEqual(out, split) def setUp(self): - self.old_parser = settings.PARSER - settings.PARSER = 'compressor.parser.LxmlParser' + self.old_parser = settings.COMPRESS_PARSER + settings.COMPRESS_PARSER = 'compressor.parser.LxmlParser' super(LxmlCompressorTestCase, self).setUp() def tearDown(self): - settings.PARSER = self.old_parser + settings.COMPRESS_PARSER = self.old_parser class CssAbsolutizingTestCase(TestCase): def setUp(self): - settings.ENABLED = True - settings.URL = '/media/' + settings.COMPRESS_ENABLED = True + settings.COMPRESS_URL = '/media/' self.css = """ @@ -152,43 +151,43 @@ class CssAbsolutizingTestCase(TestCase): def test_css_absolute_filter(self): from compressor.filters.css_default import CssAbsoluteFilter - filename = os.path.join(settings.ROOT, 'css/url/test.css') + filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') content = "p { background: url('../../images/image.gif') }" - output = "p { background: url('%simages/image.gif?%s') }" % (settings.URL, get_hashed_mtime(filename)) + output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename)) filter = CssAbsoluteFilter(content) self.assertEqual(output, filter.input(filename=filename)) - settings.URL = 'http://media.example.com/' - filename = os.path.join(settings.ROOT, 'css/url/test.css') - output = "p { background: url('%simages/image.gif?%s') }" % (settings.URL, get_hashed_mtime(filename)) + settings.COMPRESS_URL = 'http://media.example.com/' + filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') + output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename)) self.assertEqual(output, filter.input(filename=filename)) def test_css_absolute_filter_https(self): from compressor.filters.css_default import CssAbsoluteFilter - filename = os.path.join(settings.ROOT, 'css/url/test.css') + filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') content = "p { background: url('../../images/image.gif') }" - output = "p { background: url('%simages/image.gif?%s') }" % (settings.URL, get_hashed_mtime(filename)) + output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename)) filter = CssAbsoluteFilter(content) self.assertEqual(output, filter.input(filename=filename)) - settings.URL = 'https://media.example.com/' - filename = os.path.join(settings.ROOT, 'css/url/test.css') - output = "p { background: url('%simages/image.gif?%s') }" % (settings.URL, get_hashed_mtime(filename)) + settings.COMPRESS_URL = 'https://media.example.com/' + filename = os.path.join(settings.COMPRESS_ROOT, 'css/url/test.css') + output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename)) self.assertEqual(output, filter.input(filename=filename)) def test_css_absolute_filter_relative_path(self): from compressor.filters.css_default import CssAbsoluteFilter - filename = os.path.join(django_settings.TEST_DIR, 'whatever', '..', 'media', 'whatever/../css/url/test.css') + filename = os.path.join(settings.TEST_DIR, 'whatever', '..', 'media', 'whatever/../css/url/test.css') content = "p { background: url('../../images/image.gif') }" - output = "p { background: url('%simages/image.gif?%s') }" % (settings.URL, get_hashed_mtime(filename)) + output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename)) filter = CssAbsoluteFilter(content) self.assertEqual(output, filter.input(filename=filename)) - settings.URL = 'https://media.example.com/' - output = "p { background: url('%simages/image.gif?%s') }" % (settings.URL, get_hashed_mtime(filename)) + settings.COMPRESS_URL = 'https://media.example.com/' + output = "p { background: url('%simages/image.gif?%s') }" % (settings.COMPRESS_URL, get_hashed_mtime(filename)) self.assertEqual(output, filter.input(filename=filename)) def test_css_hunks(self): hash_dict = { - 'hash1': get_hashed_mtime(os.path.join(settings.ROOT, 'css/url/url1.css')), - 'hash2': get_hashed_mtime(os.path.join(settings.ROOT, 'css/url/2/url2.css')), + 'hash1': get_hashed_mtime(os.path.join(settings.COMPRESS_ROOT, 'css/url/url1.css')), + 'hash2': get_hashed_mtime(os.path.join(settings.COMPRESS_ROOT, 'css/url/2/url2.css')), } out = [u"p { background: url('/media/images/test.png?%(hash1)s'); }\np { background: url('/media/images/test.png?%(hash1)s'); }\np { background: url('/media/images/test.png?%(hash1)s'); }\np { background: url('/media/images/test.png?%(hash1)s'); }\n" % hash_dict, u"p { background: url('/media/images/test.png?%(hash2)s'); }\np { background: url('/media/images/test.png?%(hash2)s'); }\np { background: url('/media/images/test.png?%(hash2)s'); }\np { background: url('/media/images/test.png?%(hash2)s'); }\n" % hash_dict] @@ -197,19 +196,19 @@ class CssAbsolutizingTestCase(TestCase): class CssDataUriTestCase(TestCase): def setUp(self): - settings.ENABLED = True - settings.CSS_FILTERS = [ + settings.COMPRESS_ENABLED = True + settings.COMPRESS_CSS_FILTERS = [ 'compressor.filters.css_default.CssAbsoluteFilter', 'compressor.filters.datauri.CssDataUriFilter', ] - settings.URL = '/media/' + settings.COMPRESS_URL = '/media/' self.css = """ """ self.cssNode = CssCompressor(self.css) def test_data_uris(self): - datauri_hash = get_hashed_mtime(os.path.join(settings.ROOT, 'css/datauri.css')) + datauri_hash = get_hashed_mtime(os.path.join(settings.COMPRESS_ROOT, 'css/datauri.css')) out = [u'.add { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJvSURBVDjLpZPrS5NhGIf9W7YvBYOkhlkoqCklWChv2WyKik7blnNris72bi6dus0DLZ0TDxW1odtopDs4D8MDZuLU0kXq61CijSIIasOvv94VTUfLiB74fXngup7nvrnvJABJ/5PfLnTTdcwOj4RsdYmo5glBWP6iOtzwvIKSWstI0Wgx80SBblpKtE9KQs/We7EaWoT/8wbWP61gMmCH0lMDvokT4j25TiQU/ITFkek9Ow6+7WH2gwsmahCPdwyw75uw9HEO2gUZSkfyI9zBPCJOoJ2SMmg46N61YO/rNoa39Xi41oFuXysMfh36/Fp0b7bAfWAH6RGi0HglWNCbzYgJaFjRv6zGuy+b9It96N3SQvNKiV9HvSaDfFEIxXItnPs23BzJQd6DDEVM0OKsoVwBG/1VMzpXVWhbkUM2K4oJBDYuGmbKIJ0qxsAbHfRLzbjcnUbFBIpx/qH3vQv9b3U03IQ/HfFkERTzfFj8w8jSpR7GBE123uFEYAzaDRIqX/2JAtJbDat/COkd7CNBva2cMvq0MGxp0PRSCPF8BXjWG3FgNHc9XPT71Ojy3sMFdfJRCeKxEsVtKwFHwALZfCUk3tIfNR8XiJwc1LmL4dg141JPKtj3WUdNFJqLGFVPC4OkR4BxajTWsChY64wmCnMxsWPCHcutKBxMVp5mxA1S+aMComToaqTRUQknLTH62kHOVEE+VQnjahscNCy0cMBWsSI0TCQcZc5ALkEYckL5A5noWSBhfm2AecMAjbcRWV0pUTh0HE64TNf0mczcnnQyu/MilaFJCae1nw2fbz1DnVOxyGTlKeZft/Ff8x1BRssfACjTwQAAAABJRU5ErkJggg=="); }\n.python { background-image: url("/media/img/python.png?%s"); }\n.datauri { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IAAAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jqch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0 vr4MkhoXe0rZigAAAABJRU5ErkJggg=="); }\n' % datauri_hash] self.assertEqual(out, self.cssNode.hunks) @@ -264,12 +263,12 @@ def render(template_string, context_dict=None): class TemplatetagTestCase(TestCase): def setUp(self): - settings.ENABLED = True + settings.COMPRESS_ENABLED = True def test_empty_tag(self): template = u"""{% load compress %}{% compress js %}{% block js %} {% endblock %}{% endcompress %}""" - context = { 'MEDIA_URL': settings.URL } + context = { 'MEDIA_URL': settings.COMPRESS_URL } self.assertEqual(u'', render(template, context)) def test_css_tag(self): @@ -279,7 +278,7 @@ class TemplatetagTestCase(TestCase): {% endcompress %} """ - context = { 'MEDIA_URL': settings.URL } + context = { 'MEDIA_URL': settings.COMPRESS_URL } out = u'' self.assertEqual(out, render(template, context)) @@ -289,7 +288,7 @@ class TemplatetagTestCase(TestCase): {% endcompress %} """ - context = { 'MEDIA_URL': settings.URL } + context = { 'MEDIA_URL': settings.COMPRESS_URL } out = '' self.assertEqual(out, render(template, context)) @@ -299,7 +298,7 @@ class TemplatetagTestCase(TestCase): {% endcompress %} """ - context = { 'MEDIA_URL': settings.URL } + context = { 'MEDIA_URL': settings.COMPRESS_URL } out = u'' self.assertEqual(out, render(template, context)) @@ -309,7 +308,7 @@ class TemplatetagTestCase(TestCase): {% endcompress %} """ - context = { 'MEDIA_URL': settings.URL } + context = { 'MEDIA_URL': settings.COMPRESS_URL } out = u'' self.assertEqual(out, render(template, context)) @@ -319,7 +318,7 @@ class TemplatetagTestCase(TestCase): {% endcompress %} """ - context = { 'MEDIA_URL': settings.URL } + context = { 'MEDIA_URL': settings.COMPRESS_URL } out = u'' self.assertEqual(out, render(template, context)) @@ -334,7 +333,7 @@ class StorageTestCase(TestCase): def setUp(self): self._storage = storage.default_storage storage.default_storage = get_storage_class('compressor.tests.storage.TestStorage')() - settings.ENABLED = True + settings.COMPRESS_ENABLED = True def tearDown(self): storage.default_storage = self._storage @@ -346,7 +345,7 @@ class StorageTestCase(TestCase): {% endcompress %} """ - context = { 'MEDIA_URL': settings.URL } + context = { 'MEDIA_URL': settings.COMPRESS_URL } out = u'' self.assertEqual(out, render(template, context)) @@ -355,7 +354,7 @@ class VerboseTestCase(CompressorTestCase): def setUp(self): super(VerboseTestCase, self).setUp() - settings.VERBOSE = True + settings.COMPRESS_VERBOSE = True class CacheBackendTestCase(CompressorTestCase): @@ -369,11 +368,11 @@ class OfflineGenerationTestCase(TestCase): """Uses templates/test_compressor_offline.html""" def setUp(self): - self._old_compress = settings.ENABLED - settings.ENABLED = True + self._old_compress = settings.COMPRESS_ENABLED + settings.COMPRESS_ENABLED = True def tearDown(self): - settings.ENABLED = self._old_compress + settings.COMPRESS_ENABLED = self._old_compress def test_offline(self): count, result = CompressCommand().compress() @@ -384,8 +383,8 @@ class OfflineGenerationTestCase(TestCase): ]) def test_offline_with_context(self): - self._old_offline_context = settings.OFFLINE_CONTEXT - settings.OFFLINE_CONTEXT = { + self._old_offline_context = settings.COMPRESS_OFFLINE_CONTEXT + settings.COMPRESS_OFFLINE_CONTEXT = { 'color': 'blue', } count, result = CompressCommand().compress() @@ -394,4 +393,4 @@ class OfflineGenerationTestCase(TestCase): u'\n', u'', ]) - settings.OFFLINE_CONTEXT = self._old_offline_context + settings.COMPRESS_OFFLINE_CONTEXT = self._old_offline_context diff --git a/compressor/utils.py b/compressor/utils.py index 05b769d..155cd75 100644 --- a/compressor/utils.py +++ b/compressor/utils.py @@ -1,16 +1,12 @@ +import inspect import os import sys - -from django.core.exceptions import ImproperlyConfigured -from django.utils.encoding import smart_str -from django.utils.hashcompat import sha_constructor - -from compressor.cache import cache -from compressor.conf import settings -from compressor.exceptions import FilterError - from shlex import split as cmd_split +from django.conf import settings + +from compressor.exceptions import FilterError + try: any = any except NameError: @@ -20,31 +16,6 @@ except NameError: return True return False -def get_hexdigest(plaintext): - return sha_constructor(plaintext).hexdigest() - -def get_mtime_cachekey(filename): - return "django_compressor.mtime.%s" % filename - -def get_offline_cachekey(source): - return ("django_compressor.offline.%s" - % get_hexdigest("".join(smart_str(s) for s in source))) - -def get_mtime(filename): - if settings.MTIME_DELAY: - key = get_mtime_cachekey(filename) - mtime = cache.get(key) - if mtime is None: - mtime = os.path.getmtime(filename) - cache.set(key, mtime, settings.MTIME_DELAY) - return mtime - return os.path.getmtime(filename) - -def get_hashed_mtime(filename, length=12): - filename = os.path.realpath(filename) - mtime = str(int(get_mtime(filename))) - return get_hexdigest(mtime)[:length] - def get_class(class_string, exception=FilterError): """ Convert a string version of a function name to the callable object.