Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Upgrade to libsass==3.1.0. Resolves #36. Resolves #38. #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "libsass"]
path = libsass
url = git://github.com/dahlia/libsass-python.git
url = git://github.com/sass/libsass.git
2 changes: 1 addition & 1 deletion libsass
Submodule libsass updated from 030e26 to 31521e
122 changes: 50 additions & 72 deletions pysass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include <Python.h>
#include "sass_interface.h"
#include "sass_context.h"

#if PY_MAJOR_VERSION >= 3
#define PySass_IF_PY3(three, two) (three)
Expand Down Expand Up @@ -37,9 +37,13 @@ static struct PySass_Pair PySass_output_style_enum[] = {

static PyObject *
PySass_compile_string(PyObject *self, PyObject *args) {
struct sass_context *context;
struct Sass_Context *ctx;
struct Sass_Data_Context *context;
struct Sass_Options *options;
char *string, *include_paths, *image_path;
int output_style, source_comments, precision;
const char *error_message, *output_string;
Sass_Output_Style output_style;
int source_comments, error_status, precision;
PyObject *result;

if (!PyArg_ParseTuple(args,
Expand All @@ -49,30 +53,38 @@ PySass_compile_string(PyObject *self, PyObject *args) {
return NULL;
}

context = sass_new_context();
context->source_string = string;
context->options.output_style = output_style;
context->options.source_comments = source_comments;
context->options.include_paths = include_paths;
context->options.image_path = image_path;
context->options.precision = precision;
context = sass_make_data_context(string);
options = sass_data_context_get_options(context);
sass_option_set_output_style(options, output_style);
sass_option_set_source_comments(options, source_comments);
sass_option_set_include_path(options, include_paths);
sass_option_set_image_path(options, image_path);
sass_option_set_precision(options, precision);

sass_compile(context);
sass_compile_data_context(context);

ctx = sass_data_context_get_context(context);
error_status = sass_context_get_error_status(ctx);
error_message = sass_context_get_error_message(ctx);
output_string = sass_context_get_output_string(ctx);
result = Py_BuildValue(
PySass_IF_PY3("hy", "hs"),
(short int) !context->error_status,
context->error_status ? context->error_message : context->output_string
(short int) !error_status,
error_status ? error_message : output_string
);
sass_free_context(context);
sass_delete_data_context(context);
return result;
}

static PyObject *
PySass_compile_filename(PyObject *self, PyObject *args) {
struct sass_file_context *context;
struct Sass_Context *ctx;
struct Sass_File_Context *context;
struct Sass_Options *options;
char *filename, *include_paths, *image_path;
int output_style, source_comments, error_status, precision;
const char *error_message, *output_string, *source_map_string;
Sass_Output_Style output_style;
int source_comments, error_status, precision;
PyObject *source_map_filename, *result;

if (!PyArg_ParseTuple(args,
Expand All @@ -82,73 +94,41 @@ PySass_compile_filename(PyObject *self, PyObject *args) {
return NULL;
}

context = sass_new_file_context();
context->input_path = filename;
context = sass_make_file_context(filename);
options = sass_file_context_get_options(context);

if (source_comments && PySass_Bytes_Check(source_map_filename)) {
size_t source_map_file_len = PySass_Bytes_GET_SIZE(source_map_filename);
if (source_map_file_len) {
char *source_map_file = (char *) malloc(source_map_file_len + 1);
strncpy(
source_map_file,
source_map_file,
PySass_Bytes_AS_STRING(source_map_filename),
source_map_file_len + 1
);
context->options.source_map_file = source_map_file;
sass_option_set_source_map_file(options, source_map_file);
}
}
context->options.output_style = output_style;
context->options.source_comments = source_comments;
context->options.include_paths = include_paths;
context->options.image_path = image_path;
context->options.precision = precision;

sass_compile_file(context);

error_status = context->error_status;
sass_option_set_output_style(options, output_style);
sass_option_set_source_comments(options, source_comments);
sass_option_set_include_path(options, include_paths);
sass_option_set_image_path(options, image_path);
sass_option_set_precision(options, precision);

sass_compile_file_context(context);

ctx = sass_file_context_get_context(context);
error_status = sass_context_get_error_status(ctx);
error_message = sass_context_get_error_message(ctx);
output_string = sass_context_get_output_string(ctx);
source_map_string = sass_context_get_source_map_string(ctx);
result = Py_BuildValue(
PySass_IF_PY3("hyy", "hss"),
(short int) !context->error_status,
error_status ? context->error_message : context->output_string,
error_status || context->source_map_string == NULL
? ""
: context->source_map_string
);
sass_free_file_context(context);
return result;
}

static PyObject *
PySass_compile_dirname(PyObject *self, PyObject *args) {
struct sass_folder_context *context;
char *search_path, *output_path, *include_paths, *image_path;
int output_style, source_comments, precision;
PyObject *result;

if (!PyArg_ParseTuple(args,
PySass_IF_PY3("yyiiyyi", "ssiissi"),
&search_path, &output_path,
&output_style, &source_comments,
&include_paths, &image_path, precision)) {
return NULL;
}

context = sass_new_folder_context();
context->search_path = search_path;
context->output_path = output_path;
context->options.output_style = output_style;
context->options.source_comments = source_comments;
context->options.include_paths = include_paths;
context->options.image_path = image_path;
context->options.precision = precision;

sass_compile_folder(context);

result = Py_BuildValue(
PySass_IF_PY3("hy", "hs"),
(short int) !context->error_status,
context->error_status ? context->error_message : NULL
(short int) !error_status,
error_status ? error_message : output_string,
error_status || source_map_string == NULL ? "" : source_map_string
);
sass_free_folder_context(context);
sass_delete_file_context(context);
return result;
}

Expand All @@ -157,8 +137,6 @@ static PyMethodDef PySass_methods[] = {
"Compile a SASS string."},
{"compile_filename", PySass_compile_filename, METH_VARARGS,
"Compile a SASS file."},
{"compile_dirname", PySass_compile_dirname, METH_VARARGS,
"Compile several SASS files."},
{NULL, NULL, 0, NULL}
};

Expand Down
46 changes: 38 additions & 8 deletions sass.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@

from six import string_types, text_type

from _sass import (OUTPUT_STYLES, compile_dirname,
compile_filename, compile_string)
from _sass import OUTPUT_STYLES, compile_filename, compile_string

__all__ = ('MODES', 'OUTPUT_STYLES', 'SOURCE_COMMENTS', 'CompileError',
'and_join', 'compile')
Expand All @@ -46,10 +45,46 @@
class CompileError(ValueError):
"""The exception type that is raised by :func:`compile()`.
It is a subtype of :exc:`exceptions.ValueError`.

"""


def mkdirp(path):
try:
os.makedirs(path)
except OSError:
if os.path.isdir(path):
return
raise


def compile_dirname(
search_path, output_path, output_style, source_comments, include_paths,
image_path, precision,
):
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
for dirpath, _, filenames in os.walk(search_path):
filenames = [
filename for filename in filenames if filename.endswith('.scss')
]
for filename in filenames:
input_filename = os.path.join(dirpath, filename)
relpath_to_file = os.path.relpath(input_filename, search_path)
output_filename = os.path.join(output_path, relpath_to_file)
output_filename = re.sub('.scss$', '.css', output_filename)
input_filename = input_filename.encode(fs_encoding)
s, v, _ = compile_filename(
input_filename, output_style, source_comments, include_paths,
image_path, precision, None,
)
if s:
v = v.decode('UTF-8')
mkdirp(os.path.dirname(output_filename))
with open(output_filename, 'w') as output_file:
output_file.write(v)
else:
return False, v
return True, None

def compile(**kwargs):
"""There are three modes of parameters :func:`compile()` can take:
``string``, ``filename``, and ``dirname``.
Expand Down Expand Up @@ -302,11 +337,6 @@ def compile(**kwargs):
except ValueError:
raise ValueError('dirname must be a pair of (source_dir, '
'output_dir)')
else:
if isinstance(search_path, text_type):
search_path = search_path.encode(fs_encoding)
if isinstance(output_path, text_type):
output_path = output_path.encode(fs_encoding)
s, v = compile_dirname(search_path, output_path,
output_style, source_comments,
include_paths, image_path, precision)
Expand Down
73 changes: 68 additions & 5 deletions sasstests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import with_statement

import collections
import contextlib
import glob
import json
import os
Expand Down Expand Up @@ -56,7 +57,7 @@ def normalize_path(path):
'sources': ['test/a.scss'],
'sourcesContent': [],
'names': [],
'mappings': ';AAKA;EAHE,kBAAkB;;EAIpB,KAAK;IAED,OAAO'
'mappings': ';AAKA;EAHE,AAAkB;;EAKpB,AAAK;IACD,AAAO',
}

B_EXPECTED_CSS = '''\
Expand All @@ -82,13 +83,15 @@ def normalize_path(path):
'''

D_EXPECTED_CSS = '''\
@charset "UTF-8";
body {
background-color: green; }
body a {
font: '나눔고딕', sans-serif; }
'''

D_EXPECTED_CSS_WITH_MAP = '''\
@charset "UTF-8";
/* line 6, SOURCE */
body {
background-color: green; }
Expand Down Expand Up @@ -240,7 +243,8 @@ def test_compile_string(self):
'''
actual = sass.compile(string=u'a { color: blue; } /* 유니코드 */')
self.assertEqual(
u'''a {
u'''@charset "UTF-8";
a {
color: blue; }

/* 유니코드 */''',
Expand Down Expand Up @@ -458,7 +462,7 @@ def test_build_one(self):
'sources': ['../test/b.scss'],
'sourcesContent': [],
'names': [],
'mappings': ';AAAA,EAAE;EAEE,WAAW'
'mappings': ';AACA,AAAE;EACE,AAAW',
},
os.path.join(d, 'css', 'b.scss.css.map')
)
Expand All @@ -476,7 +480,7 @@ def test_build_one(self):
'sources': ['../test/d.scss'],
'sourcesContent': [],
'names': [],
'mappings': ';AAKA;EAHE,kBAAkB;;EAIpB,KAAK;IAED,MAAM'
'mappings': ';AAKA;EAHE,AAAkB;;EAKpB,AAAK;IACD,AAAM',
},
os.path.join(d, 'css', 'd.scss.css.map')
)
Expand Down Expand Up @@ -673,14 +677,73 @@ def test_sassc_sourcemap(self):
shutil.rmtree(tmp_dir)


@contextlib.contextmanager
def tempdir():
tmpdir = tempfile.mkdtemp()
try:
yield tmpdir
finally:
shutil.rmtree(tmpdir)


def write_file(filename, contents):
with open(filename, 'w') as f:
f.write(contents)


class CompileDirectoriesTest(unittest.TestCase):

def test_successful(self):
with tempdir() as tmpdir:
input_dir = os.path.join(tmpdir, 'input')
output_dir = os.path.join(tmpdir, 'output')
os.makedirs(os.path.join(input_dir, 'foo'))
write_file(os.path.join(input_dir, 'f1.scss'), 'a { b { width: 100%; } }')
write_file(os.path.join(input_dir, 'foo/f2.scss'), 'foo { width: 100%; }')
# Make sure we don't compile non-scss files
write_file(os.path.join(input_dir, 'baz.txt'), 'Hello der')

# the api for this is weird, why does it need source?
sass.compile(dirname=(input_dir, output_dir))
assert os.path.exists(output_dir)
assert os.path.exists(os.path.join(output_dir, 'foo'))
assert os.path.exists(os.path.join(output_dir, 'f1.css'))
assert os.path.exists(os.path.join(output_dir, 'foo/f2.css'))
assert not os.path.exists(os.path.join(output_dir, 'baz.txt'))

contentsf1 = open(os.path.join(output_dir, 'f1.css')).read()
contentsf2 = open(os.path.join(output_dir, 'foo/f2.css')).read()
self.assertEqual(contentsf1, 'a b {\n width: 100%; }\n')
self.assertEqual(contentsf2, 'foo {\n width: 100%; }\n')

def test_error(self):
with tempdir() as tmpdir:
input_dir = os.path.join(tmpdir, 'input')
os.makedirs(input_dir)
write_file(os.path.join(input_dir, 'bad.scss'), 'a {')

try:
sass.compile(dirname=(input_dir, os.path.join(tmpdir, 'output')))
assert False, 'Expected to raise'
except sass.CompileError as e:
msg, = e.args
assert msg.decode('UTF-8').endswith(
'bad.scss:1: invalid property name\n'
), msg
return
except Exception as e:
assert False, 'Expected to raise CompileError but got {0!r}'.format(e)


test_cases = [
SassTestCase,
CompileTestCase,
BuilderTestCase,
ManifestTestCase,
WsgiTestCase,
DistutilsTestCase,
SasscTestCase
SasscTestCase,
CompileDirectoriesTest,
]
loader = unittest.defaultTestLoader
suite = unittest.TestSuite()
Expand Down
Loading