diff --git a/django_inlinecss/conf.py b/django_inlinecss/conf.py index 8258447..dc0448e 100644 --- a/django_inlinecss/conf.py +++ b/django_inlinecss/conf.py @@ -10,12 +10,23 @@ from django.utils import importlib DEFAULT_ENGINE = 'django_inlinecss.engines.PynlinerEngine' +DEFAULT_CSS_LOADER = 'django_inlinecss.css_loaders.StaticfilesStorageCSSLoader' + + +def load_class_by_path(path): + i = path.rfind('.') + module_path, class_name = path[:i], path[i + 1:] + module = importlib.import_module(module_path) + return getattr(module, class_name) def get_engine(): from django.conf import settings engine_path = getattr(settings, 'INLINECSS_ENGINE', DEFAULT_ENGINE) - i = engine_path.rfind('.') - module_path, class_name = engine_path[:i], engine_path[i + 1:] - module = importlib.import_module(module_path) - return getattr(module, class_name) + return load_class_by_path(engine_path) + + +def get_css_loader(): + from django.conf import settings + engine_path = getattr(settings, 'INLINECSS_CSS_LOADER', DEFAULT_CSS_LOADER) + return load_class_by_path(engine_path) diff --git a/django_inlinecss/css_loaders.py b/django_inlinecss/css_loaders.py new file mode 100644 index 0000000..3021874 --- /dev/null +++ b/django_inlinecss/css_loaders.py @@ -0,0 +1,42 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from django.contrib.staticfiles import finders +from django.contrib.staticfiles.storage import staticfiles_storage + + +class BaseCSSLoader(object): + def __init__(self): + pass + + def load(self, path): + """ + Retrieves the contents of the static asset specified + :param path: path to the desired asset + :return: contents of asset + """ + raise NotImplementedError() + + +class StaticfilesFinderCSSLoader(BaseCSSLoader): + def load(self, path): + """ + Retrieve CSS contents from the local filesystem with static finders + """ + expanded_path = finders.find(path) + + if expanded_path is None: + raise IOError('{} does not exist'.format(path)) + + with open(expanded_path, 'rb') as css_file: + return css_file.read().decode('utf-8') + + +class StaticfilesStorageCSSLoader(BaseCSSLoader): + def load(self, path): + """ + Retrieve CSS contents with staticfiles storage + """ + return staticfiles_storage.open(path).read().decode('utf-8') diff --git a/django_inlinecss/templatetags/inlinecss.py b/django_inlinecss/templatetags/inlinecss.py index e6cdad1..c778ddf 100644 --- a/django_inlinecss/templatetags/inlinecss.py +++ b/django_inlinecss/templatetags/inlinecss.py @@ -4,9 +4,6 @@ from __future__ import unicode_literals from django import template -from django.conf import settings -from django.contrib.staticfiles import finders -from django.contrib.staticfiles.storage import staticfiles_storage from django.utils.encoding import smart_text from django_inlinecss import conf @@ -27,13 +24,9 @@ def render(self, context): path = expression.resolve(context, True) if path is not None: path = smart_text(path) - if settings.DEBUG: - expanded_path = finders.find(path) - else: - expanded_path = staticfiles_storage.path(path) - with open(expanded_path) as css_file: - css = ''.join((css, css_file.read())) + css_loader = conf.get_css_loader()() + css = ''.join((css, css_loader.load(path))) engine = conf.get_engine()(html=rendered_contents, css=css) return engine.render() diff --git a/django_inlinecss/tests/test_css_loaders.py b/django_inlinecss/tests/test_css_loaders.py new file mode 100644 index 0000000..f79a1c2 --- /dev/null +++ b/django_inlinecss/tests/test_css_loaders.py @@ -0,0 +1,47 @@ +""" +Test CSS loaders +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from django.conf import settings +from django.test import TestCase +from django.test import override_settings + +from django_inlinecss.css_loaders import StaticfilesFinderCSSLoader +from django_inlinecss.css_loaders import StaticfilesStorageCSSLoader + + +@override_settings(STATICFILES_DIRS=[settings.STATIC_ROOT], STATIC_ROOT='') +class StaticfilesFinderCSSLoaderTestCase(TestCase): + def setUp(self): + self.loader = StaticfilesFinderCSSLoader() + super(StaticfilesFinderCSSLoaderTestCase, self).setUp() + + def test_loads_existing_css_file(self): + css = self.loader.load('bar.css') + self.assertIn('div.bar {', css) + + def test_load_file_does_not_exist(self): + with self.assertRaises(IOError) as e: + self.loader.load('missing.css') + + self.assertEqual(str(e.exception), 'missing.css does not exist') + + +class StaticfilesStorageCSSLoaderTestCase(TestCase): + def setUp(self): + self.loader = StaticfilesStorageCSSLoader() + super(StaticfilesStorageCSSLoaderTestCase, self).setUp() + + def test_loads_existing_css_file(self): + css = self.loader.load('bar.css') + self.assertIn('div.bar {', css) + + def test_load_file_does_not_exist(self): + with self.assertRaises(IOError) as e: + self.loader.load('missing.css') + + self.assertEqual(e.exception.strerror, 'No such file or directory') diff --git a/django_inlinecss/tests/test_templatetags.py b/django_inlinecss/tests/test_templatetags.py index 2a05836..06d6227 100644 --- a/django_inlinecss/tests/test_templatetags.py +++ b/django_inlinecss/tests/test_templatetags.py @@ -28,7 +28,7 @@ def assert_foo_and_bar_rendered(self, rendered): r'
' r'\s+This is the "foo" div.\s+' r'<\/div>') - self.assertRegexpMatches( + self.assertRegex( rendered, foo_div_regex) @@ -36,7 +36,7 @@ def assert_foo_and_bar_rendered(self, rendered): r'
' r'\s+This is the "bar" div.\s+' r'<\/div>') - self.assertRegexpMatches( + self.assertRegex( rendered, bar_div_regex) @@ -120,10 +120,10 @@ def test_unicode_context_variables(self): rendered = template.render({ 'unicode_string': u'I love playing with my pi\xf1ata'}) - self.assertRegexpMatches( + self.assertRegex( rendered, '
') - self.assertRegexpMatches( + self.assertRegex( rendered, u'I love playing with my pi\xf1ata') @@ -139,37 +139,37 @@ def test_comments_are_ignored(self): template = get_template('comments_are_ignored.html') rendered = template.render({}) - self.assertRegexpMatches( + self.assertRegex( rendered, r'\s+\s+\s+') - self.assertRegexpMatches( + self.assertRegex( rendered, r'This is the "bar" div.\s+\s+') -class DebugModeStaticfilesTests(TestCase): - @override_settings(DEBUG=True) - @patch('django.contrib.staticfiles.finders.find') - def test_debug_mode_uses_staticfiles_finder(self, find): +class GetLoaderStaticfilesTests(TestCase): + @patch('django.contrib.staticfiles.storage.staticfiles_storage.path') + def test_default_uses_staticfiles_storage(self, path): full_path = os.path.join( settings.STATIC_ROOT, 'foobar.css', ) - find.return_value = full_path + path.return_value = full_path template = get_template('single_staticfiles_css.html') template.render({}) - find.assert_called_once_with("foobar.css") + path.assert_called_once_with("foobar.css") - @patch('django.contrib.staticfiles.storage.staticfiles_storage.path') - def test_non_debug_mode_uses_staticfiles_storage(self, path): + @override_settings(INLINECSS_CSS_LOADER='django_inlinecss.css_loaders.StaticfilesFinderCSSLoader') + @patch('django.contrib.staticfiles.finders.find') + def test_override_uses_staticfiles_finder(self, find): full_path = os.path.join( settings.STATIC_ROOT, 'foobar.css', ) - path.return_value = full_path + find.return_value = full_path template = get_template('single_staticfiles_css.html') template.render({}) - path.assert_called_once_with("foobar.css") + find.assert_called_once_with("foobar.css")