diff --git a/django_inlinecss/conf.py b/django_inlinecss/conf.py index 85e63dd..fb72158 100644 --- a/django_inlinecss/conf.py +++ b/django_inlinecss/conf.py @@ -6,10 +6,26 @@ DEFAULT_ENGINE = 'django_inlinecss.engines.PynlinerEngine' +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 + + if settings.DEBUG: + default_css_loader = 'django_inlinecss.css_loaders.StaticFinderCSSLoader' + else: + default_css_loader = 'django_inlinecss.css_loaders.StaticPathCSSLoader' + + 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..5aaf59d --- /dev/null +++ b/django_inlinecss/css_loaders.py @@ -0,0 +1,38 @@ +from django.contrib.staticfiles import finders +from django.contrib.staticfiles.storage import staticfiles_storage + + +def load_css_by_path(path): + with open(path) as css_file: + return css_file.read() + + +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 StaticFinderCSSLoader(BaseCSSLoader): + def load(self, path): + """ + Retrieve CSS contents by static finders + """ + expanded_path = finders.find(path) + return load_css_by_path(expanded_path) + + +class StaticPathCSSLoader(BaseCSSLoader): + def load(self, path): + """ + Retrieve CSS contents by local file system + """ + expanded_path = staticfiles_storage.path(path) + return load_css_by_path(expanded_path) diff --git a/django_inlinecss/templatetags/inlinecss.py b/django_inlinecss/templatetags/inlinecss.py index f1f8213..a957119 100644 --- a/django_inlinecss/templatetags/inlinecss.py +++ b/django_inlinecss/templatetags/inlinecss.py @@ -22,13 +22,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..d392646 --- /dev/null +++ b/django_inlinecss/tests/test_css_loaders.py @@ -0,0 +1,52 @@ +""" +Test CSS loaders +""" +import os + +from django.test import TestCase +from django.test.utils import override_settings + +from mock import patch + +from django_inlinecss.tests.constants import TESTS_STATIC_DIR +from django_inlinecss.css_loaders import StaticFinderCSSLoader, StaticPathCSSLoader + + +@override_settings(STATIC_ROOT=TESTS_STATIC_DIR) +class StaticFinderCSSLoaderTestCase(TestCase): + def setUp(self): + self.loader = StaticFinderCSSLoader() + super(StaticFinderCSSLoaderTestCase, self).setUp() + + @patch('django.contrib.staticfiles.finders.find') + def test_debug_mode_uses_staticfiles_finder(self, find): + full_path = os.path.join(TESTS_STATIC_DIR, 'bar.css') + find.return_value = full_path + css = self.loader.load(full_path) + self.assertIn('div.bar {', css) + + @patch('django.contrib.staticfiles.finders.find') + def test_load_file_does_not_exists(self, find): + full_path = os.path.join(TESTS_STATIC_DIR, 'missing.css') + find.return_value = full_path + with self.assertRaises(IOError) as e: + self.loader.load('missing.css') + + self.assertEqual(e.exception.strerror, 'No such file or directory') + + +@override_settings(STATIC_ROOT=TESTS_STATIC_DIR) +class StaticPathCSSLoaderTestCase(TestCase): + def setUp(self): + self.loader = StaticPathCSSLoader() + super(StaticPathCSSLoaderTestCase, self).setUp() + + def test_load_existing_css_file(self): + css = self.loader.load('bar.css') + self.assertIn('div.bar {', css) + + def test_load_file_does_not_exists(self): + with self.assertRaises(IOError) as e: + self.loader.load('missing.css') + + self.assertEqual(e.exception.strerror, 'No such file or directory')