summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEevee (Alex Munroe) <eevee.git@veekun.com>2014-03-29 22:17:20 -0700
committerEevee (Alex Munroe) <eevee.git@veekun.com>2014-03-29 22:17:20 -0700
commit4a1b03a499dd07c37628f0bae8e36b9deaf1c7d4 (patch)
treeff33111291f67ede32da4ab4ed3b1ff652336a0d
parent5ba6063e623c8f6726479682bcdfd3f5923f33ee (diff)
downloadpyscss-4a1b03a499dd07c37628f0bae8e36b9deaf1c7d4.tar.gz
Write CSS out in the same encoding it claims to be.
-rw-r--r--scss/__init__.py16
-rw-r--r--scss/cssdefs.py12
-rw-r--r--scss/tool.py27
3 files changed, 37 insertions, 18 deletions
diff --git a/scss/__init__.py b/scss/__init__.py
index 24ac7d8..865e996 100644
--- a/scss/__init__.py
+++ b/scss/__init__.py
@@ -48,7 +48,6 @@ __license__ = LICENSE
from collections import defaultdict
import glob
-import io
from itertools import product
import logging
import warnings
@@ -160,8 +159,8 @@ class SourceFile(object):
@classmethod
def from_file(cls, f, filename, **kwargs):
- encoding = determine_encoding(f)
contents = f.read()
+ encoding = determine_encoding(contents)
if isinstance(contents, six.binary_type):
contents = contents.decode(encoding)
@@ -172,9 +171,9 @@ class SourceFile(object):
if isinstance(string, six.text_type):
# Already decoded; we don't know what encoding to use for output,
# though, so still check for a @charset.
- encoding = determine_encoding(io.StringIO(string))
+ encoding = determine_encoding(string)
elif isinstance(string, six.binary_type):
- encoding = determine_encoding(io.BytesIO(string))
+ encoding = determine_encoding(string)
string = string.decode(encoding)
else:
raise TypeError("Expected a string, got {0!r}".format(string))
@@ -393,13 +392,17 @@ class Scss(object):
#@profile
#@print_timing(2)
- def Compilation(self, scss_string=None, scss_file=None, super_selector=None, filename=None, is_sass=None, line_numbers=True):
+ def Compilation(self, scss_string=None, scss_file=None, source_files=None, super_selector=None, filename=None, is_sass=None, line_numbers=True):
+ # TODO this signature is totally wacky; it should just take a list of
+ # source files
if super_selector:
self.super_selector = super_selector + ' '
self.reset()
source_file = None
- if scss_string is not None:
+ if source_files is not None:
+ self.source_files = source_files
+ elif scss_string is not None:
source_file = SourceFile.from_string(scss_string, filename, is_sass, line_numbers)
elif scss_file is not None:
source_file = SourceFile.from_filename(scss_file, filename, is_sass, line_numbers)
@@ -1264,6 +1267,7 @@ class Scss(object):
"""
Implements @-blocks
"""
+ # TODO handle @charset, probably?
# Interpolate the current block
# TODO this seems like it should be done in the block header. and more
# generally?
diff --git a/scss/cssdefs.py b/scss/cssdefs.py
index 398a4cc..e312ca5 100644
--- a/scss/cssdefs.py
+++ b/scss/cssdefs.py
@@ -347,16 +347,12 @@ def is_builtin_css_function(name):
# CSS character set determination
# Based upon: http://www.w3.org/TR/CSS2/syndata.html#charset
-def determine_encoding(f):
- """Return the appropriate encoding for the given file, according to the CSS
- charset rules.
+def determine_encoding(buf):
+ """Return the appropriate encoding for the given CSS source, according to
+ the CSS charset rules.
- `f` should be a file-like object with the cursor at the beginning.
+ `buf` may be either a string or bytes.
"""
- # 200 bytes should be enough for anyone
- buf = f.read(200)
- f.seek(0)
-
# The ultimate default is utf8; bravo, W3C
bom_encoding = 'UTF-8'
diff --git a/scss/tool.py b/scss/tool.py
index d765c8f..6b15a37 100644
--- a/scss/tool.py
+++ b/scss/tool.py
@@ -163,19 +163,38 @@ def run_tests():
def do_build(options, args):
if options.output is not None:
- output = open(options.output, 'wt')
+ out = open(options.output, 'wb')
else:
- output = sys.stdout
+ out = sys.stdout
+ # Get the unencoded stream on Python 3
+ out = getattr(out, 'buffer', out)
css = Scss(scss_opts={
'style': options.style,
'debug_info': options.debug_info,
})
if args:
+ source_files = [
+ SourceFile.from_filename(path, is_sass=options.is_sass)
+ for path in args
+ ]
for path in args:
- output.write(css.compile(scss_file=path, is_sass=options.is_sass))
+ out.write(css.compile(scss_file=path, is_sass=options.is_sass))
else:
- output.write(css.compile(sys.stdin.read(), is_sass=options.is_sass))
+ source_files = [
+ SourceFile.from_file(sys.stdin, "<stdin>", is_sass=options.is_sass)]
+
+ encodings = set(source.encoding for source in source_files)
+ if len(encodings) > 1:
+ sys.stderr.write(
+ "Can't combine these files! "
+ "They have different encodings: {0}\n"
+ .format(', '.join(encodings))
+ )
+ sys.exit(3)
+
+ output = css.compile(source_files=source_files)
+ out.write(output.encode(source_files[0].encoding))
for f, t in profiling.items():
sys.stderr.write("%s took %03fs" % (f, t))