Permalink
Browse files

Merge branch 'release/0.6.1'

  • Loading branch information...
2 parents 7130cd7 + 95eef66 commit 5b0fd7e6f5b9c91f8cd2b97249fb3b15d028fb97 @jezdez jezdez committed Apr 13, 2011
View
@@ -15,8 +15,16 @@ Brad Whittington
Chris Adams
David Ziegler
Eugene Mirotin
+Fenn Bailey
Gert Van Gool
+Jason Davies
+Jeremy Dunck
Justin Lilly
Maciek Szczesniak
+Mathieu Pillard
Mehmet S. Catalbas
-Ulrich Petri
+Petar Radosevic
+Philipp Wollermann
+Shabda Raaj
+Thom Linton
+Ulrich Petri
@@ -1,4 +1,4 @@
-VERSION = (0, 6, 0, "f", 0) # following PEP 386
+VERSION = (0, 6, 1, "f", 0) # following PEP 386
DEV_N = None
View
@@ -12,7 +12,7 @@
from compressor.exceptions import CompressorError, UncompressableFileError
from compressor.filters import CompilerFilter
from compressor.storage import default_storage
-from compressor.utils import get_class, cached_property
+from compressor.utils import get_class, cached_property, get_staticfiles_finders
class Compressor(object):
@@ -30,6 +30,7 @@ def __init__(self, content=None, output_prefix="compressed"):
self.split_content = []
self.extra_context = {}
self.all_mimetypes = dict(settings.COMPRESS_PRECOMPILERS)
+ self.finders = get_staticfiles_finders()
def split_contents(self):
"""
@@ -50,9 +51,19 @@ def get_filename(self, url):
basename = url.replace(base_url, "", 1)
# drop the querystring, which is used for non-compressed cache-busting.
basename = basename.split("?", 1)[0]
+ # first try finding the file in the root
filename = os.path.join(settings.COMPRESS_ROOT, basename)
if not os.path.exists(filename):
- raise UncompressableFileError("'%s' does not exist" % filename)
+ # if not found and staticfiles is installed, use it
+ if self.finders:
+ filename = self.finders.find(basename)
+ if filename:
+ return filename
+ # or just raise an exception as the last resort
+ raise UncompressableFileError(
+ "'%s' could not be found in the COMPRESS_ROOT '%s'%s" % (
+ basename, settings.COMPRESS_ROOT,
+ self.finders and " or with staticfiles." or "."))
return filename
@cached_property
View
@@ -44,14 +44,13 @@ def split_contents(self):
def output(self, *args, **kwargs):
# Populate self.split_content
- self.split_contents()
- if not hasattr(self, 'media_nodes'):
- return super(CssCompressor, self).output(*args, **kwargs)
if (settings.COMPRESS_ENABLED or settings.COMPRESS_PRECOMPILERS or
kwargs.get('forced', False)):
- ret = []
- for media, subnode in self.media_nodes:
- subnode.extra_context.update({'media': media})
- ret.append(subnode.output(*args, **kwargs))
- return ''.join(ret)
- return self.content
+ self.split_contents()
+ if hasattr(self, 'media_nodes'):
+ ret = []
+ for media, subnode in self.media_nodes:
+ subnode.extra_context.update({'media': media})
+ ret.append(subnode.output(*args, **kwargs))
+ return ''.join(ret)
+ return super(CssCompressor, self).output(*args, **kwargs)
View
@@ -2,19 +2,17 @@
from compressor.conf import settings
from compressor.storage import CompressorFileStorage
+from compressor.utils import get_staticfiles_finders
-if "django.contrib.staticfiles" in settings.INSTALLED_APPS:
- from django.contrib.staticfiles.finders import BaseStorageFinder
-elif "staticfiles" in settings.INSTALLED_APPS:
- from staticfiles.finders import BaseStorageFinder
-else:
+finders = get_staticfiles_finders()
+if finders is None:
raise ImproperlyConfigured("When using the compressor staticfiles finder"
"either django.contrib.staticfiles or the "
"standalone version django-staticfiles needs "
"to be installed.")
-class CompressorFinder(BaseStorageFinder):
+class CompressorFinder(finders.BaseStorageFinder):
"""
A staticfiles finder that looks in COMPRESS_ROOT
for compressed files, to be used during development
@@ -78,7 +78,7 @@ def configure_root(self, value):
if ("compressor.finders.CompressorFinder" not in
staticfiles_settings.STATICFILES_FINDERS):
raise ImproperlyConfigured(
- "When using django_compressor together with staticfiles, "
+ "When using Django Compressor together with staticfiles, "
"please add 'compressor.finders.CompressorFinder' to the "
"STATICFILES_FINDERS setting.")
return value
@@ -48,35 +48,64 @@ def cache_set(self, key, val, refreshed=False,
def cache_key(self, compressor):
return "%s.%s.%s" % (compressor.cachekey, self.mode, self.kind)
- def render(self, context, forced=False, debug=False):
+ 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:
- debug = settings.COMPRESS_DEBUG_TOGGLE in request.GET
+ return settings.COMPRESS_DEBUG_TOGGLE in request.GET
+
+ def render_offline(self, forced):
+ """
+ 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 and not debug:
- content = cache.get(get_offline_cachekey(self.nodelist))
- if content:
- return content
- content = self.nodelist.render(context)
- if debug:
- return content
- compressor = self.compressor_cls(content)
- cachekey = self.cache_key(compressor)
- output = self.cache_get(cachekey)
- if output is None or forced:
- try:
- output = compressor.output(self.mode, forced=forced)
- self.cache_set(cachekey, output)
- except:
- if settings.DEBUG or forced:
- from traceback import format_exc
- raise Exception(format_exc())
- else:
- return content
- return output
+ settings.COMPRESS_OFFLINE) and not forced:
+ return cache.get(get_offline_cachekey(self.nodelist))
+
+ def render_cached(self, 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 = self.cache_key(compressor)
+ cache_content = self.cache_get(cache_key)
+ return cache_key, cache_content
+ return None, None
+
+ def render(self, context, forced=False):
+ # 1. Check if in debug mode
+ if self.debug_mode(context):
+ return self.nodelist.render(context)
+
+ # 2. Try offline cache.
+ cached_offline = self.render_offline(forced)
+ if cached_offline:
+ return cached_offline
+
+ # 3. Prepare the actual compressor and check cache
+ compressor = self.compressor_cls(self.nodelist.render(context))
+ cache_key, cache_content = self.render_cached(compressor, forced)
+ if cache_content is not None:
+ return cache_content
+
+ # 4. call compressor output method and handle exceptions
+ try:
+ rendered_output = compressor.output(self.mode, forced=forced)
+ if cache_key:
+ self.cache_set(cache_key, rendered_output)
+ return rendered_output
+ except:
+ if settings.DEBUG or forced:
+ # Be very loud about the exception we just encountered
+ from traceback import format_exc
+ raise Exception(format_exc())
+
+ # 5. Or don't do anything in production
+ return self.nodelist.render(context)
@register.tag
def compress(parser, token):
View
@@ -531,3 +531,17 @@ def format(self, *args, **kwargs):
params[str(id(item))] = _format_field(value, parts, conv, spec,
want_bytes)
return self._string % params
+
+
+def get_staticfiles_finders():
+ finders = None
+ if ('staticfiles' in settings.INSTALLED_APPS or
+ 'django.contrib.staticfiles' in settings.INSTALLED_APPS):
+ try:
+ from django.contrib.staticfiles import finders
+ except ImportError:
+ try:
+ from staticfiles import finders
+ except ImportError:
+ pass
+ return finders
View
@@ -0,0 +1,69 @@
+Changelog
+=========
+
+0.6.1
+-----
+
+- Fixed staticfiles support to also use its finder API to find files during
+ developement -- when the static files haven't been collected in
+ ``STATIC_ROOT``.
+
+- Fixed regression with the ``COMPRESS`` setting, pre-compilation and
+ staticfiles.
+
+0.6
+---
+
+Major improvements and a lot of bugfixes, some of which are:
+
+- New precompilation support, which allows compilation of files and
+ hunks with easily configurable compilers before calling the actual
+ output filters. See the
+ :ref:`COMPRESS_PRECOMPILERS <compress_precompilers>` for more details.
+
+- New staticfiles support. With the introduction of the staticfiles app
+ to Django 1.3, compressor officially supports finding the files to
+ compress using the app's finder API. Have a look at the documentation
+ about :ref:`remote storages <remote_storages>` in case you want to use
+ those together with compressor.
+
+- New ``compress`` management command which allows pre-running of what the
+ compress template tag does. See the
+ :ref:`pre-compression <pre-compression>` docs for more information.
+
+- Various perfomance improvements by better caching and mtime cheking.
+
+- Deprecated ``COMPRESS_LESSC_BINARY`` setting because it's now
+ superseded by the :ref:`COMPRESS_PRECOMPILERS <compress_precompilers>`
+ setting. Just make sure to use the correct mimetype when linking to less
+ files or adding inline code and add the following to your settings::
+
+ COMPRESS_PRECOMPILERS = (
+ ('text/less', 'lessc {infile} {outfile}'),
+ )
+
+- Added cssmin_ filter (``compressor.filters.CSSMinFilter``) based on
+ Zachary Voase's Python port of the YUI CSS compression algorithm.
+
+- Reimplemented the dog-piling prevention.
+
+- Make sure the CssAbsoluteFilter works for relative paths.
+
+- Added inline render mode. See :ref:`usage <usage>` docs.
+
+- Added ``mtime_cache`` management command to add and/or remove all mtimes
+ from the cache.
+
+- Moved docs to Read The Docs: http://django_compressor.readthedocs.org
+
+- Added optional ``compressor.storage.GzipCompressorFileStorage`` storage
+ backend that gzips of the saved files automatically for easier deployment.
+
+- Reimplemented a few filters on top of the new
+ ``compressor.filters.base.CompilerFilter`` to be a bit more DRY.
+
+- Added tox based test configuration, testing on Django 1.1-1.3 and Python
+ 2.5-2.7.
+
+.. _cssmin: http://pypi.python.org/pypi/cssmin/
+
View
@@ -50,7 +50,7 @@
# The short X.Y version.
version = '0.6'
# The full version, including alpha/beta/rc tags.
-release = '0.6'
+release = '0.6.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
View
@@ -40,4 +40,4 @@ Contents
settings
remote-storages
behind-the-scenes
-
+ changelog
View
@@ -16,7 +16,7 @@ Installation
default behaviour and make adjustements for your website.
* In case you use Django 1.3's staticfiles_ contrib app (or its standalone
- clone django-staticfiles_) you have to add django_compressor's file finder
+ clone django-staticfiles_) you have to add Django Compressor's file finder
to the ``STATICFILES_FINDERS`` setting::
STATICFILES_FINDERS = (
@@ -58,11 +58,3 @@ Deprecation
This section lists features and settings that are deprecated or removed
in newer versions of Django Compressor.
-* ``COMPRESS_LESSC_BINARY``
- Superseded by the :ref:`COMPRESS_PRECOMPILERS <compress_precompilers>`
- setting. Just make sure to use the correct mimetype when linking to less
- files or adding inline code and add the following to your settings::
-
- COMPRESS_PRECOMPILERS = (
- ('text/less', 'lessc {infile} {outfile}'),
- )
@@ -1,3 +1,5 @@
+.. _remote_storages:
+
Remote storages
---------------
Oops, something went wrong.

0 comments on commit 5b0fd7e

Please sign in to comment.