diff options
author | Rocky Meza <rocky@fusionbox.com> | 2014-02-01 19:29:22 -0700 |
---|---|---|
committer | Rocky Meza <rocky@fusionbox.com> | 2014-02-01 19:29:22 -0700 |
commit | 64cb29c8bb81c1b7ed9fbc08966dd918f4a12ca0 (patch) | |
tree | f137a4eda3a036d01485fd42c84732626fe432e7 | |
parent | 2a53a7abd1ddba02c44b81a24305b03532b45fee (diff) | |
download | django-pyscss-64cb29c8bb81c1b7ed9fbc08966dd918f4a12ca0.tar.gz |
updated to PyScss 1.2.0
-rw-r--r-- | django_pyscss/scss.py | 90 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | tests/test_import.py | 14 |
3 files changed, 69 insertions, 37 deletions
diff --git a/django_pyscss/scss.py b/django_pyscss/scss.py index 9837436..5990d2b 100644 --- a/django_pyscss/scss.py +++ b/django_pyscss/scss.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, unicode_literals +import os import fnmatch from django.contrib.staticfiles import finders @@ -7,8 +8,7 @@ from django.contrib.staticfiles.storage import staticfiles_storage from django.conf import settings from scss import ( - Scss, dequote, log, spawn_rule, - OPTIONS, PROPERTIES, + Scss, dequote, log, SourceFile, SassRule, ) @@ -42,53 +42,77 @@ class DjangoScss(Scss): # remote storages don't implement path pass finally: - with staticfiles_storage.open(filename) as f: - return f.read() + return filename, staticfiles_storage def get_file_from_finders(self, filename): - path, storage = find_one_file(filename) - with storage.open(path) as f: - return f.read() + return find_one_file(filename) - def get_file_contents(self, filename): + def get_file_and_storage(self, filename): # TODO: the switch probably shouldn't be on DEBUG if settings.DEBUG: return self.get_file_from_finders(filename) else: return self.get_file_from_storage(filename) - def _do_import(self, rule, p_selectors, p_parents, p_children, scope, media, c_lineno, c_property, c_codestr, code, name): + def _find_source_file(self, name): + full_filename, storage = self.get_file_and_storage(name) + if name not in self.source_files: + with storage.open(full_filename) as f: + source = f.read() + source_file = SourceFile( + full_filename, + source, + parent_dir=os.path.realpath(os.path.dirname(full_filename)), + ) + self.source_files.append(source_file) + self.source_file_index[full_filename] = source_file + return self.source_file_index[full_filename] + + def _do_import(self, rule, scope, block): """ Implements @import using the django storages API. """ # Protect against going to prohibited places... - if '..' in name or '://' in name or 'url(' in name: - rule[PROPERTIES].append((c_lineno, c_property, None)) + if any(scary_token in block.argument for scary_token in ('..', '://', 'url(')): + rule.properties.append((block.prop, None)) return full_filename = None - i_codestr = None - names = name.split(',') - for filename in names: - filename = dequote(name.strip()) - if '@import ' + filename in rule[OPTIONS]: + names = block.argument.split(',') + for name in names: + name = dequote(name.strip()) + + source_file = self._find_source_file(name) + + if source_file is None: + i_codestr = self._do_magic_import(rule, scope, block) + + if i_codestr is not None: + source_file = SourceFile.from_string(i_codestr) + self.source_files.append(source_file) + self.source_file_index[full_filename] = source_file + + if source_file is None: + log.warn("File to import not found or unreadable: '%s' (%s)", name, rule.file_and_line) + continue + + import_key = (name, source_file.parent_dir) + if rule.namespace.has_import(import_key): # If already imported in this scope, skip continue - try: - i_codestr = self.scss_files[filename] - except KeyError: - i_codestr = self.get_file_contents(filename) - - if i_codestr is None: - i_codestr = self._do_magic_import(rule, p_selectors, p_parents, p_children, scope, media, c_lineno, c_property, c_codestr, code, name) - if i_codestr is None: - log.warn("I couldn't find this file (%s)." % filename) - - i_codestr = self.scss_files[name] = i_codestr and self.load_string(i_codestr, full_filename) - if name not in self.scss_files: - self._scss_files_order.append(name) - if i_codestr is not None: - _rule = spawn_rule(rule, codestr=i_codestr, path=full_filename, lineno=c_lineno) - self.manage_children(_rule, p_selectors, p_parents, p_children, scope, media) - rule[OPTIONS]['@import ' + name] = True + _rule = SassRule( + source_file=source_file, + lineno=block.lineno, + import_key=import_key, + unparsed_contents=source_file.contents, + + # rule + options=rule.options, + properties=rule.properties, + extends_selectors=rule.extends_selectors, + ancestry=rule.ancestry, + namespace=rule.namespace, + ) + rule.namespace.add_import(import_key, rule.import_key, rule.file_and_line) + self.manage_children(_rule, scope) @@ -14,7 +14,7 @@ def read(fname): install_requires = [ 'Django>=1.3', - 'PyScss>=1.1.5', + 'PyScss>=1.2.0', ] version = (0, 0, 1, 'final') diff --git a/tests/test_import.py b/tests/test_import.py index 1fdab51..6e65de5 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -40,18 +40,26 @@ IMPORT_APP2 = """ APP2_CONTENTS = FOO_CONTENTS + APP1_CONTENTS +def clean_css(string): + # The output of the compiled CSS doesn't have a newline between the ; and + # the } for some reason. + return string.strip() \ + .replace('\n', '') \ + .replace('; ', ';') + + class ImportTestMixin(object): def test_import_from_staticfiles_dirs(self): actual = compile_string(IMPORT_FOO) - self.assertEqual(actual.strip(), FOO_CONTENTS.strip()) + self.assertEqual(clean_css(actual), clean_css(FOO_CONTENTS)) def test_import_from_app(self): actual = compile_string(IMPORT_APP1) - self.assertEqual(actual.strip(), APP1_CONTENTS.strip()) + self.assertEqual(clean_css(actual), clean_css(APP1_CONTENTS)) def test_imports_within_file(self): actual = compile_string(IMPORT_APP2) - self.assertEqual(actual.strip(), APP2_CONTENTS.strip()) + self.assertEqual(clean_css(actual), clean_css(APP2_CONTENTS)) @override_settings(DEBUG=True) |