summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEevee <eevee.github@veekun.com>2013-10-04 16:49:10 -0700
committerEevee <eevee.github@veekun.com>2013-10-04 16:49:10 -0700
commitfa4567204284da17c10cc368c4100e5785e577fa (patch)
tree622cc7b19abce287e4727c205dce8261e6eafcc2
parente6ec63d3db24334dcc902027abfdf09c53cdaa51 (diff)
parent0dec6bc74f19a01356dc9fb650e287a546dd5dbc (diff)
downloadpyscss-fa4567204284da17c10cc368c4100e5785e577fa.tar.gz
Merge pull request #213 from funvit/master
issue_212
-rw-r--r--scss/config.py4
-rw-r--r--scss/functions/compass/helpers.py103
-rw-r--r--scss/functions/compass/images.py134
-rw-r--r--scss/tests/files/cursors/fake.base64.txt1
-rw-r--r--scss/tests/files/cursors/fake.cur1
-rw-r--r--scss/tests/files/fonts/bgrove.base64.txt1
-rw-r--r--scss/tests/files/fonts/bgrove.ttfbin0 -> 18744 bytes
-rw-r--r--scss/tests/files/images/test-qr.base64.txt1
-rw-r--r--scss/tests/files/images/test-qr.pngbin0 -> 855 bytes
-rw-r--r--scss/tests/functions/compass/test_helpers.py46
-rw-r--r--scss/tests/functions/compass/test_images.py61
-rw-r--r--scss/tool.py22
12 files changed, 272 insertions, 102 deletions
diff --git a/scss/config.py b/scss/config.py
index 60d8bc5..2ecadb4 100644
--- a/scss/config.py
+++ b/scss/config.py
@@ -14,6 +14,10 @@ CACHE_ROOT = None
# Urls for the static and assets:
STATIC_URL = 'static/'
ASSETS_URL = 'static/assets/'
+FONTS_ROOT = STATIC_ROOT
+FONTS_URL = STATIC_URL
+IMAGES_ROOT = STATIC_ROOT
+IMAGES_URL = STATIC_URL
VERBOSITY = True
STYLE = 'nested'
FATAL_UNDEFINED = True
diff --git a/scss/functions/compass/helpers.py b/scss/functions/compass/helpers.py
index db98cec..e5bb159 100644
--- a/scss/functions/compass/helpers.py
+++ b/scss/functions/compass/helpers.py
@@ -20,12 +20,22 @@ from scss import config
from scss.functions.library import FunctionLibrary
from scss.types import Boolean, List, Null, Number, String
from scss.util import escape, to_str
+import re
log = logging.getLogger(__name__)
COMPASS_HELPERS_LIBRARY = FunctionLibrary()
register = COMPASS_HELPERS_LIBRARY.register
+FONT_TYPES = {
+ 'woff': 'woff',
+ 'otf': 'opentype',
+ 'opentype': 'opentype',
+ 'ttf': 'truetype',
+ 'truetype': 'truetype',
+ 'svg': 'svg',
+ 'eot': 'embedded-opentype'
+}
def add_cache_buster(url, mtime):
fragment = url.split('#')
@@ -488,73 +498,78 @@ COMPASS_HELPERS_LIBRARY.add(Number.wrap_python_function(math.tan), 'tan', 1)
def _font_url(path, only_path=False, cache_buster=True, inline=False):
filepath = String.unquoted(path).value
- path = None
- if callable(config.STATIC_ROOT):
+ file = None
+ if callable(config.FONTS_ROOT):
try:
- _file, _storage = list(config.STATIC_ROOT(filepath))[0]
+ _file, _storage = list(config.FONTS_ROOT(filepath))[0]
d_obj = _storage.modified_time(_file)
filetime = int(time.mktime(d_obj.timetuple()))
if inline:
- path = _storage.open(_file)
+ file = _storage.open(_file)
except:
filetime = 'NA'
else:
- _path = os.path.join(config.STATIC_ROOT, filepath.strip('/'))
+ _path = os.path.join(config.FONTS_ROOT, filepath.strip('/'))
if os.path.exists(_path):
filetime = int(os.path.getmtime(_path))
if inline:
- path = open(_path, 'rb')
+ file = open(_path, 'rb')
else:
filetime = 'NA'
- BASE_URL = config.STATIC_URL
-
- if path and inline:
- mime_type = mimetypes.guess_type(filepath)[0]
- url = 'data:' + mime_type + ';base64,' + base64.b64encode(path.read())
+ BASE_URL = config.FONTS_URL
+
+ if file and inline:
+# mime_type = mimetypes.guess_type(filepath)[0]
+ font_type = None
+ if re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value):
+ font_type = String.unquoted(re.match(r'^([^?]+)[.](.*)([?].*)?$', path.value).groups()[1]).value
+
+ if not FONT_TYPES.get(font_type):
+ raise Exception('Could not determine font type for "%s"' % path.value)
+
+ mime = FONT_TYPES.get(font_type)
+ if font_type == 'woff':
+ mime = 'application/font-woff'
+ elif font_type=='eot':
+ mime = 'application/vnd.ms-fontobject'
+ url = 'data:' + (mime if '/' in mime else 'font/%s' % mime) + ';base64,' + base64.b64encode(file.read())
+ file.close()
else:
- url = '%s%s' % (BASE_URL, filepath)
- if cache_buster:
+ url = '%s/%s' % (BASE_URL.rstrip('/'), filepath.lstrip('/'))
+ if cache_buster and filetime != 'NA':
url = add_cache_buster(url, filetime)
if not only_path:
- url = 'url("%s")' % escape(url)
+ url = 'url(%s)' % escape(url)
return String.unquoted(url)
def _font_files(args, inline):
- args = List.from_maybe_starargs(args)
- n = 0
- params = [[], []]
- for arg in args:
- if isinstance(arg, List):
- if len(arg) == 2:
- if n % 2 == 1:
- params[1].append(None)
- n += 1
- params[0].append(arg[0])
- params[1].append(arg[1])
- n += 2
- else:
- for arg2 in arg:
- params[n % 2].append(arg2)
- n += 1
- else:
- params[n % 2].append(arg)
- n += 1
- len0 = len(params[0])
- len1 = len(params[1])
- if len1 < len0:
- params[1] += [None] * (len0 - len1)
- elif len0 < len1:
- params[0] += [None] * (len1 - len0)
+ if args == ():
+ return String.unquoted("")
+
fonts = []
- for font, format in zip(params[0], params[1]):
- if format:
- fonts.append('%s format("%s")' % (_font_url(font, inline=inline), String.unquoted(format).value))
+ args_len = len(args)
+ skip_next = False
+ for index in xrange(len(args)):
+ arg = args[index]
+ if not skip_next:
+ font_type = args[index + 1] if args_len > (index +1) else None
+ if font_type and FONT_TYPES.has_key(font_type.value):
+ skip_next = True
+ else:
+ if re.match(r'^([^?]+)[.](.*)([?].*)?$', arg.value):
+ font_type = String.unquoted(re.match(r'^([^?]+)[.](.*)([?].*)?$', arg.value).groups()[1])
+
+ if FONT_TYPES.has_key(font_type.value):
+ fonts.append(String.unquoted('%s format("%s")' % (_font_url(arg, inline=inline), String.unquoted(FONT_TYPES[font_type.value]).value)))
+ else:
+ raise Exception('Could not determine font type for "%s"' % arg.value)
else:
- fonts.append(_font_url(font, inline=inline))
- return List(fonts)
+ skip_next = False
+ return List(fonts, separator=',')
+
@register('font-url', 1)
@register('font-url', 2)
diff --git a/scss/functions/compass/images.py b/scss/functions/compass/images.py
index 4f5e312..675c19e 100644
--- a/scss/functions/compass/images.py
+++ b/scss/functions/compass/images.py
@@ -49,9 +49,9 @@ def _image_url(path, only_path=False, cache_buster=True, dst_color=None, src_col
filepath = String.unquoted(path).value
mime_type = inline and (String.unquoted(mime_type).value if mime_type else mimetypes.guess_type(filepath)[0])
path = None
- if callable(config.STATIC_ROOT):
+ if callable(config.IMAGES_ROOT):
try:
- _file, _storage = list(config.STATIC_ROOT(filepath))[0]
+ _file, _storage = list(config.IMAGES_ROOT(filepath))[0]
d_obj = _storage.modified_time(_file)
filetime = int(time.mktime(d_obj.timetuple()))
if inline or dst_color or spacing:
@@ -59,14 +59,14 @@ def _image_url(path, only_path=False, cache_buster=True, dst_color=None, src_col
except:
filetime = 'NA'
else:
- _path = os.path.join(config.STATIC_ROOT, filepath.strip('/'))
+ _path = os.path.join(config.IMAGES_ROOT.rstrip('/'), filepath.strip('/'))
if os.path.exists(_path):
filetime = int(os.path.getmtime(_path))
if inline or dst_color or spacing:
path = open(_path, 'rb')
else:
filetime = 'NA'
- BASE_URL = config.STATIC_URL
+ BASE_URL = config.IMAGES_URL
if path:
dst_colors = [list(Color(v).value[:3]) for v in List.from_maybe(dst_color) if v]
@@ -100,56 +100,80 @@ def _image_url(path, only_path=False, cache_buster=True, dst_color=None, src_col
filetime = int(os.path.getmtime(asset_path))
url = add_cache_buster(url, filetime)
else:
- image = Image.open(path)
- width, height = collapse_x or image.size[0], collapse_y or image.size[1]
- new_image = Image.new(
- mode='RGBA',
- size=(width + spacing[1] + spacing[3], height + spacing[0] + spacing[2]),
- color=(0, 0, 0, 0)
- )
- for i, dst_color in enumerate(dst_colors):
- src_color = src_colors[i]
- pixdata = image.load()
- for _y in xrange(image.size[1]):
- for _x in xrange(image.size[0]):
- pixel = pixdata[_x, _y]
- if pixel[:3] == src_color:
- pixdata[_x, _y] = tuple([int(c) for c in dst_color] + [pixel[3] if len(pixel) == 4 else 255])
- iwidth, iheight = image.size
- if iwidth != width or iheight != height:
- cy = 0
- while cy < iheight:
- cx = 0
- while cx < iwidth:
- cropped_image = image.crop((cx, cy, cx + width, cy + height))
- new_image.paste(cropped_image, (int(spacing[3]), int(spacing[0])), cropped_image)
- cx += width
- cy += height
+ simply_process = False
+ image = None
+
+ if _path.split('.')[-1] in ['cur']:
+ simply_process = True
else:
- new_image.paste(image, (int(spacing[3]), int(spacing[0])))
-
- if not inline:
try:
- new_image.save(asset_path)
- filepath = asset_file
- BASE_URL = config.ASSETS_URL
+ image = Image.open(path)
+ except IOError, e:
+ if not collapse_x and not collapse_y and not dst_colors:
+ simply_process = True
+
+ if simply_process:
+ if not mime_type:
+ mime_type = 'image/%s' % _path.split('.')[-1]
+ if inline:
+ url = 'data:' + mime_type + ';base64,' + base64.b64encode(path.read())
+ else:
+ url = '%s%s' % (BASE_URL, filepath)
if cache_buster:
filetime = int(os.path.getmtime(asset_path))
- except IOError:
- log.exception("Error while saving image")
- inline = True # Retry inline version
- url = '%s%s' % (config.ASSETS_URL, asset_file)
- if cache_buster:
- url = add_cache_buster(url, filetime)
- if inline:
- output = six.BytesIO()
- new_image.save(output, format='PNG')
- contents = output.getvalue()
- output.close()
- url = 'data:' + mime_type + ';base64,' + base64.b64encode(contents)
+ url = add_cache_buster(url, filetime)
+ else:
+ width, height = collapse_x or image.size[0], collapse_y or image.size[1]
+ new_image = Image.new(
+ mode='RGBA',
+ size=(width + spacing[1] + spacing[3], height + spacing[0] + spacing[2]),
+ color=(0, 0, 0, 0)
+ )
+ for i, dst_color in enumerate(dst_colors):
+ src_color = src_colors[i]
+ pixdata = image.load()
+ for _y in xrange(image.size[1]):
+ for _x in xrange(image.size[0]):
+ pixel = pixdata[_x, _y]
+ if pixel[:3] == src_color:
+ pixdata[_x, _y] = tuple([int(c) for c in dst_color] + [pixel[3] if len(pixel) == 4 else 255])
+ iwidth, iheight = image.size
+ if iwidth != width or iheight != height:
+ cy = 0
+ while cy < iheight:
+ cx = 0
+ while cx < iwidth:
+ cropped_image = image.crop((cx, cy, cx + width, cy + height))
+ new_image.paste(cropped_image, (int(spacing[3]), int(spacing[0])), cropped_image)
+ cx += width
+ cy += height
+ else:
+ new_image.paste(image, (int(spacing[3]), int(spacing[0])))
+
+ if not inline:
+ try:
+ new_image.save(asset_path)
+ filepath = asset_file
+ BASE_URL = config.ASSETS_URL
+ if cache_buster:
+ filetime = int(os.path.getmtime(asset_path))
+ except IOError:
+ log.exception("Error while saving image")
+ inline = True # Retry inline version
+ url = os.path.join(config.ASSETS_URL.rstrip('/'), asset_file.lstrip('/'))
+ if cache_buster:
+ url = add_cache_buster(url, filetime)
+ if inline:
+ output = six.BytesIO()
+ new_image.save(output, format='PNG')
+ contents = output.getvalue()
+ output.close()
+ if not mime_type:
+ mime_type = 'image/%s' % _path.split('.')[-1]
+ url = 'data:' + mime_type + ';base64,' + base64.b64encode(contents)
else:
- url = '%s%s' % (BASE_URL, filepath)
- if cache_buster:
+ url = os.path.join(BASE_URL.rstrip('/'), filepath.lstrip('/'))
+ if cache_buster and filetime != 'NA':
url = add_cache_buster(url, filetime)
if not only_path:
@@ -202,14 +226,14 @@ def image_width(image):
width = _image_size_cache[filepath][0]
except KeyError:
width = 0
- if callable(config.STATIC_ROOT):
+ if callable(config.IMAGES_ROOT):
try:
- _file, _storage = list(config.STATIC_ROOT(filepath))[0]
+ _file, _storage = list(config.IMAGES_ROOT(filepath))[0]
path = _storage.open(_file)
except:
pass
else:
- _path = os.path.join(config.STATIC_ROOT, filepath.strip('/'))
+ _path = os.path.join(config.IMAGES_ROOT, filepath.strip('/'))
if os.path.exists(_path):
path = open(_path, 'rb')
if path:
@@ -234,14 +258,14 @@ def image_height(image):
height = _image_size_cache[filepath][1]
except KeyError:
height = 0
- if callable(config.STATIC_ROOT):
+ if callable(config.IMAGES_ROOT):
try:
- _file, _storage = list(config.STATIC_ROOT(filepath))[0]
+ _file, _storage = list(config.IMAGES_ROOT(filepath))[0]
path = _storage.open(_file)
except:
pass
else:
- _path = os.path.join(config.STATIC_ROOT, filepath.strip('/'))
+ _path = os.path.join(config.IMAGES_ROOT, filepath.strip('/'))
if os.path.exists(_path):
path = open(_path, 'rb')
if path:
diff --git a/scss/tests/files/cursors/fake.base64.txt b/scss/tests/files/cursors/fake.base64.txt
new file mode 100644
index 0000000..d2b0610
--- /dev/null
+++ b/scss/tests/files/cursors/fake.base64.txt
@@ -0,0 +1 @@
+b213ZHQzNDV2MzRmNWRtODR0dXJlOGc4OXVpaDQzNTh5M3Y0Nzh0dzRwOTh0dWc5OGRmeWdlcjY4N3lldWl5N2VyeXQ4Nw== \ No newline at end of file
diff --git a/scss/tests/files/cursors/fake.cur b/scss/tests/files/cursors/fake.cur
new file mode 100644
index 0000000..ff27014
--- /dev/null
+++ b/scss/tests/files/cursors/fake.cur
@@ -0,0 +1 @@
+86374tomwdt345v34f5dm84ture8g89uih4358y3v478tw4p98tug98dfyger687yeuiy7eryt87 \ No newline at end of file
diff --git a/scss/tests/files/fonts/bgrove.base64.txt b/scss/tests/files/fonts/bgrove.base64.txt
new file mode 100644
index 0000000..56d0b5e
--- /dev/null
+++ b/scss/tests/files/fonts/bgrove.base64.txt
@@ -0,0 +1 @@
+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 \ No newline at end of file
diff --git a/scss/tests/files/fonts/bgrove.ttf b/scss/tests/files/fonts/bgrove.ttf
new file mode 100644
index 0000000..9f2d056
--- /dev/null
+++ b/scss/tests/files/fonts/bgrove.ttf
Binary files differ
diff --git a/scss/tests/files/images/test-qr.base64.txt b/scss/tests/files/images/test-qr.base64.txt
new file mode 100644
index 0000000..0931544
--- /dev/null
+++ b/scss/tests/files/images/test-qr.base64.txt
@@ -0,0 +1 @@
+iVBORw0KGgoAAAANSUhEUgAAALgAAAC4CAYAAABQMybHAAADQUlEQVR4nO3dQVIjMRAAwfUG///y7A+sg0LbmiLzDNjYFTq0G/F5nuf5A1F/p58AnCRw0gROmsBJEzhpAidN4KT9rL7g8/n8j+cxZvUxwPTvv/sxxfTzP231+jjBSRM4aQInTeCkCZw0gZMmcNKWc/CV29fJd+fA03Py1c/fff3r758TnDSBkyZw0gROmsBJEzhpAidtew6+cnpOfHqOe3qOfru3v39OcNIETprASRM4aQInTeCkCZy043Pwt5u+l+Ttc/RpTnDSBE6awEkTOGkCJ03gpAmcNHPww07P0c3Jv3OCkyZw0gROmsBJEzhpAidN4KQdn4O/fU47PYeefv2mH3+XE5w0gZMmcNIETprASRM4aQInbXsOfvr+6LfbnaOfnsPX3z8nOGkCJ03gpAmcNIGTJnDSBE7a53n7wu/l3A8+ywlOmsBJEzhpAidN4KQJnDSBk7bcB799n3nl9Bz69D719D749M/f/X4nOGkCJ03gpAmcNIGTJnDSBE7acg7+9jnw7fvU089ves59mhOcNIGTJnDSBE6awEkTOGkCJ217H3zX6X3hldP7yNP3b5+eU9/+9wBOcNIETprASRM4aQInTeCkCZy04/vgt+8bT8+pV6b34afvN9/9fic4aQInTeCkCZw0gZMmcNIETtry/2TePic+7fY5/u2Pv8v94PCFwEkTOGkCJ03gpAmcNIGTtr0PXle/d2V6Tn76cxYnOGkCJ03gpAmcNIGTJnDSBE7a+P3g06bv7ViZnsPffr/4ihOcNIGTJnDSBE6awEkTOGkCJ205B1+5fV98eo686/Qc+/TjT3/O4AQnTeCkCZw0gZMmcNIETprASdueg69Mz4lPm7635LTb701xPzi/msBJEzhpAidN4KQJnDSBk3Z8Dl53et/6dvbBYZDASRM4aQInTeCkCZw0gZNmDr4w/X8sd92+z73LPji/msBJEzhpAidN4KQJnDSBk3Z8Dv72fefpOffuHHv39Z+eo+9ygpMmcNIETprASRM4aQInTeCkbc/Bp/edT5veB5+eY0//fu4Hhy8ETprASRM4aQInTeCkCZy0z3P7Qi9scIKTJnDSBE6awEkTOGkCJ03gpP0DbikWfcrVj3kAAAAASUVORK5CYII= \ No newline at end of file
diff --git a/scss/tests/files/images/test-qr.png b/scss/tests/files/images/test-qr.png
new file mode 100644
index 0000000..094d03e
--- /dev/null
+++ b/scss/tests/files/images/test-qr.png
Binary files differ
diff --git a/scss/tests/functions/compass/test_helpers.py b/scss/tests/functions/compass/test_helpers.py
index 0d52956..50c0c7f 100644
--- a/scss/tests/functions/compass/test_helpers.py
+++ b/scss/tests/functions/compass/test_helpers.py
@@ -16,6 +16,9 @@ from scss.rule import Namespace
import pytest
+from scss import config
+import os
+from _pytest.monkeypatch import monkeypatch
xfail = pytest.mark.xfail
# TODO many of these tests could also stand to test for failure cases
@@ -145,14 +148,53 @@ def test_pow(calc):
## Fonts
-
# font-url
+def test_font_url(calc):
+ assert calc('font-url("/some_path.woff")').render() == ('url(%(static_url)ssome_path.woff)' % {'static_url': config.FONTS_URL})
+ assert calc('font-url("/some_path.woff") format("woff")').render() == ('url(%(static_url)ssome_path.woff) format("woff")' % {'static_url': config.FONTS_URL})
+
# font-files
+def test_font_files(calc):
+ """
+ @author: funvit
+ @note: adapted from compass / test / units / sass_extensions_test.rb
+ """
+ assert '' == calc('font-files()').render()
+ assert ('url(%(static_url)sfont/name.woff) format("woff"), url(%(static_url)sfonts/name.ttf) format("truetype"), url(%(static_url)sfonts/name.svg#fontpath) format("svg")' % {'static_url': config.FONTS_URL}) == calc('font-files("/font/name.woff", woff, "/fonts/name.ttf", truetype, "/fonts/name.svg#fontpath", svg)').render()
+
+ assert ('url(%(static_url)sfont/with/right_ext.woff) format("woff")' % {'static_url': config.FONTS_URL}) == calc('font_files("/font/with/right_ext.woff")').render()
+ assert ('url(%(static_url)sfont/with/wrong_ext.woff) format("svg")' % {'static_url': config.FONTS_URL}) == calc('font_files("/font/with/wrong_ext.woff", "svg")').render()
+ assert ('url(%(static_url)sfont/with/no_ext) format("opentype")' % {'static_url': config.FONTS_URL}) == calc('font_files("/font/with/no_ext", "otf")').render()
+ assert ('url(%(static_url)sfont/with/weird.ext) format("truetype")' % {'static_url': config.FONTS_URL}) == calc('font_files("/font/with/weird.ext", "truetype")').render()
+
+ assert ('url(%(static_url)sfont/with/right_ext.woff) format("woff"), url(%(static_url)sfont/with/right_ext_also.otf) format("opentype")' % {'static_url': config.FONTS_URL}) == calc('font_files("/font/with/right_ext.woff", "/font/with/right_ext_also.otf")').render()
+ assert ('url(%(static_url)sfont/with/wrong_ext.woff) format("truetype"), url(%(static_url)sfont/with/right_ext.otf) format("opentype")' % {'static_url': config.FONTS_URL}) == calc('font_files("/font/with/wrong_ext.woff", "ttf", "/font/with/right_ext.otf")').render()
+
# inline-font-files
-
+def test_inline_font_files(calc):
+ """
+ @author: funvit
+ @note: adapted from compass / test / units / sass_extensions_test.rb
+ """
+# def mockreturn(path):
+# return os.path.join(config.PROJECT_ROOT, 'tests/files/fonts', path.strip('/'))
+
+ monkeypatch().setattr(config, 'FONTS_ROOT', os.path.join(config.PROJECT_ROOT, 'tests/files/fonts'))
+
+ f = open(os.path.join(config.PROJECT_ROOT, 'tests/files/fonts/bgrove.base64.txt'), 'r')
+ font_base64 = ''.join((f.readlines()))
+ f.close()
+ assert 'url(data:font/truetype;base64,%s) format("truetype")' % font_base64 == calc('inline_font_files("/bgrove.ttf", truetype)').render()
## External stylesheets
# stylesheet-url
+
+
+# for debugging uncomment next lines
+#if __name__=='__main__':
+# test_font_url(calc())
+# test_font_files(calc())
+# test_inline_font_files(calc()) \ No newline at end of file
diff --git a/scss/tests/functions/compass/test_images.py b/scss/tests/functions/compass/test_images.py
new file mode 100644
index 0000000..b6f8c72
--- /dev/null
+++ b/scss/tests/functions/compass/test_images.py
@@ -0,0 +1,61 @@
+"""Tests for the Compass images functions.
+
+Not all of Compass is implemented, and the arrangement of Compass functions
+doesn't exactly match the arrangement in the original documentation.
+Regardless, this is a good starting place:
+
+http://compass-style.org/reference/compass/helpers/
+
+Some functions appear to be undocumented, but nonetheless are part of Compass's
+Ruby code.
+"""
+
+from scss.expression import Calculator
+from scss.functions.compass.images import COMPASS_IMAGES_LIBRARY
+from scss.rule import Namespace
+
+
+import pytest
+from scss import config
+import os
+from _pytest.monkeypatch import monkeypatch
+xfail = pytest.mark.xfail
+
+# TODO many of these tests could also stand to test for failure cases
+
+
+@pytest.fixture
+def calc():
+ ns = Namespace(functions=COMPASS_IMAGES_LIBRARY)
+ return Calculator(ns).evaluate_expression
+
+
+def test_image_url(calc):
+ assert calc('image-url("/some_path.jpg")').render() == ('url(%(images_url)ssome_path.jpg)' % {'images_url': config.IMAGES_URL})
+
+
+# inline-image
+def test_inline_image(calc):
+ monkeypatch().setattr(config, 'IMAGES_ROOT', os.path.join(config.PROJECT_ROOT, 'tests/files/images'))
+
+ f = open(os.path.join(config.PROJECT_ROOT, 'tests/files/images/test-qr.base64.txt'), 'rb')
+ font_base64 = f.read()
+ f.close()
+ assert 'url(data:image/png;base64,%s)' % font_base64 == calc('inline_image("/test-qr.png")').render()
+
+
+def test_inline_cursor(calc):
+ monkeypatch().setattr(config, 'IMAGES_ROOT', os.path.join(config.PROJECT_ROOT, 'tests/files/cursors'))
+
+ f = open(os.path.join(config.PROJECT_ROOT, 'tests/files/cursors/fake.base64.txt'), 'rb')
+ font_base64 = f.read()
+ f.close()
+ assert 'url(data:image/cur;base64,%s)' % font_base64 == calc('inline_image("/fake.cur")').render()
+
+
+
+# for debugging uncomment next lines
+if __name__=='__main__':
+# test_image_url(calc())
+# test_inline_image(calc())
+# test_inline_cursor(calc())
diff --git a/scss/tool.py b/scss/tool.py
index 7e4aef0..c9753c0 100644
--- a/scss/tool.py
+++ b/scss/tool.py
@@ -55,7 +55,7 @@ def main():
parser.add_option("-t", "--style", metavar="NAME",
dest="style", default='nested',
help="Output style. Can be nested (default), compact, compressed, or expanded.")
- parser.add_option("-C", "--no-compress", action="store_false", dest="style",
+ parser.add_option("-C", "--no-compress", action="store_false", dest="style", default=True,
help="Don't minify outputted CSS")
parser.add_option("-?", action="help", help=SUPPRESS_HELP)
parser.add_option("-h", "--help", action="help",
@@ -73,6 +73,14 @@ def main():
help="Assets root path (Sprite images will be created here)")
paths_group.add_option("-a", "--assets-url", metavar="URL", dest="assets_url",
help="URL to reach the files in your assets_root")
+ paths_group.add_option("-F", "--fonts-root", metavar="PATH", dest="fonts_root",
+ help="Fonts root path (Where fonts are located)")
+ paths_group.add_option("-f", "--fonts-url", metavar="PATH", dest="fonts_url",
+ help="URL to reach the fonts in your fonts_root")
+ paths_group.add_option("--images-root", metavar="PATH", dest="images_root",
+ help="Images root path (Where images are located)")
+ paths_group.add_option("--images-url", metavar="PATH", dest="images_url",
+ help="URL to reach the images in your images_root")
paths_group.add_option("--cache-root", metavar="PATH", dest="cache_root",
help="Cache root path (Cache files will be created here)")
parser.add_option_group(paths_group)
@@ -87,10 +95,22 @@ def main():
config.VERBOSITY = 0
if options.time:
config.VERBOSITY = 2
+
if options.static_root is not None:
config.STATIC_ROOT = options.static_root
if options.assets_root is not None:
config.ASSETS_ROOT = options.assets_root
+
+ if options.fonts_root is not None:
+ config.FONTS_ROOT = options.fonts_root
+ if options.fonts_url is not None:
+ config.FONTS_URL = options.fonts_url
+
+ if options.images_root is not None:
+ config.IMAGES_ROOT = options.images_root
+ if options.images_url is not None:
+ config.IMAGES_URL = options.images_url
+
if options.cache_root is not None:
config.CACHE_ROOT = options.cache_root
if options.load_paths is not None: