Merge pull request #653 from karyon/always_apply_absolute

apply CssAbsoluteFilter to precompiled css even when compression is disabled
This commit is contained in:
Mathieu Pillard
2015-09-24 20:38:30 +02:00
3 changed files with 61 additions and 9 deletions

View File

@@ -21,6 +21,7 @@ from compressor.conf import settings
from compressor.exceptions import (CompressorError, UncompressableFileError, from compressor.exceptions import (CompressorError, UncompressableFileError,
FilterDoesNotExist) FilterDoesNotExist)
from compressor.filters import CachedCompilerFilter from compressor.filters import CachedCompilerFilter
from compressor.filters.css_default import CssAbsoluteFilter
from compressor.storage import compressor_file_storage from compressor.storage import compressor_file_storage
from compressor.signals import post_compress from compressor.signals import post_compress
from compressor.utils import get_class, get_mod_func, staticfiles from compressor.utils import get_class, get_mod_func, staticfiles
@@ -211,20 +212,24 @@ class Compressor(object):
precompiled, value = self.precompile(value, **options) precompiled, value = self.precompile(value, **options)
if enabled: if enabled:
yield self.filter(value, **options) yield self.filter(value, self.cached_filters, **options)
elif precompiled:
# since precompiling moves files around, it breaks url()
# statements in css files. therefore we run the absolute filter
# on precompiled css files even if compression is disabled.
if CssAbsoluteFilter in self.cached_filters:
value = self.filter(value, [CssAbsoluteFilter], **options)
yield self.handle_output(kind, value, forced=True,
basename=basename)
else: else:
if precompiled: yield self.parser.elem_str(elem)
yield self.handle_output(kind, value, forced=True,
basename=basename)
else:
yield self.parser.elem_str(elem)
def filter_output(self, content): def filter_output(self, content):
""" """
Passes the concatenated content to the 'output' methods Passes the concatenated content to the 'output' methods
of the compressor filters. of the compressor filters.
""" """
return self.filter(content, method=METHOD_OUTPUT) return self.filter(content, self.cached_filters, method=METHOD_OUTPUT)
def filter_input(self, forced=False): def filter_input(self, forced=False):
""" """
@@ -275,8 +280,8 @@ class Compressor(object):
filename=filename) filename=filename)
return True, filter.input(**kwargs) return True, filter.input(**kwargs)
def filter(self, content, method, **kwargs): def filter(self, content, filters, method, **kwargs):
for filter_cls in self.cached_filters: for filter_cls in filters:
filter_func = getattr( filter_func = getattr(
filter_cls(content, filter_type=self.type), method) filter_cls(content, filter_type=self.type), method)
try: try:

View File

@@ -0,0 +1 @@
p { background: url('../img/python.png'); }

View File

@@ -48,9 +48,55 @@ class TestPrecompiler(object):
return 'OUTPUT' return 'OUTPUT'
class PassthroughPrecompiler(object):
"""A filter whose outputs the input unmodified """
def __init__(self, content, attrs, filter_type=None, filename=None,
charset=None):
self.content = content
def input(self, **kwargs):
return self.content
test_dir = os.path.abspath(os.path.join(os.path.dirname(__file__))) test_dir = os.path.abspath(os.path.join(os.path.dirname(__file__)))
class PrecompilerAndAbsoluteFilterTestCase(SimpleTestCase):
def setUp(self):
self.html_orig = '<link rel="stylesheet" href="/static/css/relative_url.css" type="text/css" />'
self.html_link_to_precompiled_css = '<link rel="stylesheet" href="/static/CACHE/css/relative_url.41a74f6d5864.css" type="text/css" />'
self.html_link_to_absolutized_css = '<link rel="stylesheet" href="/static/CACHE/css/relative_url.9b8fd415e521.css" type="text/css" />'
self.css_orig = "p { background: url('../img/python.png'); }" # content of relative_url.css
self.css_absolutized = "p { background: url('/static/img/python.png?c2281c83670e'); }"
def helper(self, enabled, use_precompiler, use_absolute_filter, expected_output):
precompiler = (('text/css', 'compressor.tests.test_base.PassthroughPrecompiler'),) if use_precompiler else ()
filters = ('compressor.filters.css_default.CssAbsoluteFilter',) if use_absolute_filter else ()
with self.settings(COMPRESS_ENABLED=enabled, COMPRESS_PRECOMPILERS=precompiler, COMPRESS_CSS_FILTERS=filters):
css_node = CssCompressor(self.html_orig)
output = list(css_node.hunks())[0]
self.assertEqual(output, expected_output)
@override_settings(COMPRESS_CSS_HASHING_METHOD="content")
def test_precompiler_enables_absolute(self):
"""
Tests whether specifying a precompiler also runs the CssAbsoluteFilter even if
compression is disabled, but only if the CssAbsoluteFilter is actually contained
in the filters setting.
While at it, ensure that everything runs as expected when compression is enabled.
"""
self.helper(enabled=False, use_precompiler=False, use_absolute_filter=False, expected_output=self.html_orig)
self.helper(enabled=False, use_precompiler=False, use_absolute_filter=True, expected_output=self.html_orig)
self.helper(enabled=False, use_precompiler=True, use_absolute_filter=False, expected_output=self.html_link_to_precompiled_css)
self.helper(enabled=False, use_precompiler=True, use_absolute_filter=True, expected_output=self.html_link_to_absolutized_css)
self.helper(enabled=True, use_precompiler=False, use_absolute_filter=False, expected_output=self.css_orig)
self.helper(enabled=True, use_precompiler=False, use_absolute_filter=True, expected_output=self.css_absolutized)
self.helper(enabled=True, use_precompiler=True, use_absolute_filter=False, expected_output=self.css_orig)
self.helper(enabled=True, use_precompiler=True, use_absolute_filter=True, expected_output=self.css_absolutized)
class CompressorTestCase(SimpleTestCase): class CompressorTestCase(SimpleTestCase):
def setUp(self): def setUp(self):