Skip to content

Commit

Permalink
Merge pull request #246 from samuelcolvin/custom_import_extensions
Browse files Browse the repository at this point in the history
support custom import extension
  • Loading branch information
asottile authored Apr 24, 2018
2 parents b0a6e51 + a1f146b commit 2b3361d
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 11 deletions.
26 changes: 21 additions & 5 deletions pysass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,17 @@ static void _add_custom_importers(
sass_option_set_c_importers(options, importer_list);
}

static void _add_custom_import_extensions(
struct Sass_Options* options, PyObject* custom_import_extensions
) {
Py_ssize_t i;

for (i = 0; i < PyList_GET_SIZE(custom_import_extensions); i += 1) {
PyObject* ext = PyList_GET_ITEM(custom_import_extensions, i);
sass_option_push_import_extension(options, PyBytes_AS_STRING(ext));
}
}

static PyObject *
PySass_compile_string(PyObject *self, PyObject *args) {
struct Sass_Context *ctx;
Expand All @@ -516,13 +527,15 @@ PySass_compile_string(PyObject *self, PyObject *args) {
int source_comments, error_status, precision, indented;
PyObject *custom_functions;
PyObject *custom_importers;
PyObject *custom_import_extensions;
PyObject *result;

if (!PyArg_ParseTuple(args,
PySass_IF_PY3("yiiyiOiO", "siisiOiO"),
PySass_IF_PY3("yiiyiOiOO", "siisiOiOO"),
&string, &output_style, &source_comments,
&include_paths, &precision,
&custom_functions, &indented, &custom_importers)) {
&custom_functions, &indented, &custom_importers,
&custom_import_extensions)) {
return NULL;
}

Expand All @@ -535,6 +548,7 @@ PySass_compile_string(PyObject *self, PyObject *args) {
sass_option_set_is_indented_syntax_src(options, indented);
_add_custom_functions(options, custom_functions);
_add_custom_importers(options, custom_importers);
_add_custom_import_extensions(options, custom_import_extensions);
sass_compile_data_context(context);

ctx = sass_data_context_get_context(context);
Expand All @@ -560,14 +574,15 @@ PySass_compile_filename(PyObject *self, PyObject *args) {
Sass_Output_Style output_style;
int source_comments, error_status, precision;
PyObject *source_map_filename, *custom_functions, *custom_importers,
*result, *output_filename_hint;
*result, *output_filename_hint, *custom_import_extensions;

if (!PyArg_ParseTuple(args,
PySass_IF_PY3("yiiyiOOOO", "siisiOOOO"),
PySass_IF_PY3("yiiyiOOOOO", "siisiOOOOO"),
&filename, &output_style, &source_comments,
&include_paths, &precision,
&source_map_filename, &custom_functions,
&custom_importers, &output_filename_hint)) {
&custom_importers, &output_filename_hint,
&custom_import_extensions)) {
return NULL;
}

Expand All @@ -594,6 +609,7 @@ PySass_compile_filename(PyObject *self, PyObject *args) {
sass_option_set_precision(options, precision);
_add_custom_functions(options, custom_functions);
_add_custom_importers(options, custom_importers);
_add_custom_import_extensions(options, custom_import_extensions);
sass_compile_file_context(context);

ctx = sass_file_context_get_context(context);
Expand Down
25 changes: 22 additions & 3 deletions sass.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def _raise(e):

def compile_dirname(
search_path, output_path, output_style, source_comments, include_paths,
precision, custom_functions, importers
precision, custom_functions, importers, custom_import_extensions
):
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
for dirpath, _, filenames in os.walk(search_path, onerror=_raise):
Expand All @@ -240,6 +240,7 @@ def compile_dirname(
s, v, _ = _sass.compile_filename(
input_filename, output_style, source_comments, include_paths,
precision, None, custom_functions, importers, None,
custom_import_extensions,
)
if s:
v = v.decode('UTF-8')
Expand Down Expand Up @@ -292,6 +293,9 @@ def compile(**kwargs):
:type custom_functions: :class:`set`,
:class:`collections.abc.Sequence`,
:class:`collections.abc.Mapping`
:param custom_import_extensions: optional extra file extensions which
allow can be imported, eg. ``['.css']``
:type custom_import_extensions: :class:`list`, :class:`tuple`
:param indented: optional declaration that the string is Sass, not SCSS
formatted. :const:`False` by default
:type indented: :class:`bool`
Expand Down Expand Up @@ -332,6 +336,9 @@ def compile(**kwargs):
:type custom_functions: :class:`set`,
:class:`collections.abc.Sequence`,
:class:`collections.abc.Mapping`
:param custom_import_extensions: optional extra file extensions which
allow can be imported, eg. ``['.css']``
:type custom_import_extensions: :class:`list`, :class:`tuple`
:param importers: optional callback functions.
see also below `importer callbacks
<importer-callbacks_>`_ description
Expand Down Expand Up @@ -374,6 +381,9 @@ def compile(**kwargs):
:type custom_functions: :class:`set`,
:class:`collections.abc.Sequence`,
:class:`collections.abc.Mapping`
:param custom_import_extensions: optional extra file extensions which
allow can be imported, eg. ``['.css']``
:type custom_import_extensions: :class:`list`, :class:`tuple`
:raises sass.CompileError: when it fails for any reason
(for example the given Sass has broken syntax)
Expand Down Expand Up @@ -584,6 +594,14 @@ def _get_file_arg(key):
'not {1!r}'.format(SassFunction, custom_functions)
)

_custom_exts = kwargs.pop('custom_import_extensions', []) or []
if not isinstance(_custom_exts, (list, tuple)):
raise TypeError(
'custom_import_extensions must be a list of strings '
'not {}'.format(type(_custom_exts))
)
custom_import_extensions = [ext.encode('utf-8') for ext in _custom_exts]

importers = _validate_importers(kwargs.pop('importers', None))

if 'string' in modes:
Expand All @@ -597,7 +615,7 @@ def _get_file_arg(key):
_check_no_remaining_kwargs(compile, kwargs)
s, v = _sass.compile_string(
string, output_style, source_comments, include_paths, precision,
custom_functions, indented, importers,
custom_functions, indented, importers, custom_import_extensions,
)
if s:
return v.decode('utf-8')
Expand All @@ -613,7 +631,7 @@ def _get_file_arg(key):
s, v, source_map = _sass.compile_filename(
filename, output_style, source_comments, include_paths, precision,
source_map_filename, custom_functions, importers,
output_filename_hint,
output_filename_hint, custom_import_extensions,
)
if s:
v = v.decode('utf-8')
Expand All @@ -631,6 +649,7 @@ def _get_file_arg(key):
s, v = compile_dirname(
search_path, output_path, output_style, source_comments,
include_paths, precision, custom_functions, importers,
custom_import_extensions
)
if s:
return
Expand Down
12 changes: 9 additions & 3 deletions sassc.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def main(argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr):
'(output css filename).')
parser.add_option('-I', '--include-path', metavar='DIR',
dest='include_paths', action='append',
help='Path to find "@import"ed (S)CSS source files. '
help='Path to find "@import"ed (S)CSS source files. '
'Can be multiply used.')
parser.add_option(
'-p', '--precision', action='store', type='int', default=5,
Expand All @@ -101,6 +101,10 @@ def main(argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr):
'--source-comments', action='store_true', default=False,
help='Include debug info in output',
)
parser.add_option('--import-extensions',
dest='custom_import_extensions', action='append',
help='Extra extensions allowed for sass imports. '
'Can be multiply used.')
options, args = parser.parse_args(argv[1:])
error = functools.partial(print,
parser.get_prog_name() + ': error:',
Expand Down Expand Up @@ -130,7 +134,8 @@ def main(argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr):
source_map_filename=source_map_filename,
output_filename_hint=args[1],
include_paths=options.include_paths,
precision=options.precision
precision=options.precision,
custom_import_extensions=options.custom_import_extensions,
)
else:
source_map_filename = None
Expand All @@ -140,7 +145,8 @@ def main(argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr):
output_style=options.style,
source_comments=options.source_comments,
include_paths=options.include_paths,
precision=options.precision
precision=options.precision,
custom_import_extensions=options.custom_import_extensions,
)
except (IOError, OSError) as e:
error(e)
Expand Down
56 changes: 56 additions & 0 deletions sasstests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1409,3 +1409,59 @@ def test_imports_from_cwd(tmpdir):
with tmpdir.as_cwd():
out = sass.compile(filename=main_scss.strpath)
assert out == ''


def test_import_no_css(tmpdir):
tmpdir.join('other.css').write('body {color: green}')
main_scss = tmpdir.join('main.scss')
main_scss.write("@import 'other';")
with pytest.raises(sass.CompileError):
sass.compile(filename=main_scss.strpath)


@pytest.mark.parametrize('exts', [
('.css',),
['.css'],
['.foobar', '.css'],
])
def test_import_css(exts, tmpdir):
tmpdir.join('other.css').write('body {color: green}')
main_scss = tmpdir.join('main.scss')
main_scss.write("@import 'other';")
out = sass.compile(
filename=main_scss.strpath,
custom_import_extensions=exts,
)
assert out == 'body {\n color: green; }\n'


def test_import_css_error(tmpdir):
tmpdir.join('other.css').write('body {color: green}')
main_scss = tmpdir.join('main.scss')
main_scss.write("@import 'other';")
with pytest.raises(TypeError):
sass.compile(
filename=main_scss.strpath,
custom_import_extensions='.css',
)


def test_import_css_string(tmpdir):
tmpdir.join('other.css').write('body {color: green}')
with tmpdir.as_cwd():
out = sass.compile(
string="@import 'other';",
custom_import_extensions=['.css'],
)
assert out == 'body {\n color: green; }\n'


def test_import_ext_other(tmpdir):
tmpdir.join('other.foobar').write('body {color: green}')
main_scss = tmpdir.join('main.scss')
main_scss.write("@import 'other';")
out = sass.compile(
filename=main_scss.strpath,
custom_import_extensions=['.foobar'],
)
assert out == 'body {\n color: green; }\n'

0 comments on commit 2b3361d

Please sign in to comment.