@@ -272,8 +272,8 @@ static union Sass_Value* _unknown_type_to_sass_error(PyObject* value) {
272272 return retv;
273273}
274274
275- static union Sass_Value* _exception_to_sass_error () {
276- union Sass_Value * retv = NULL ;
275+ static PyObject* _exception_to_bytes () {
276+ PyObject * retv = NULL ;
277277 PyObject* etype = NULL ;
278278 PyObject* evalue = NULL ;
279279 PyObject* etb = NULL ;
@@ -287,22 +287,34 @@ static union Sass_Value* _exception_to_sass_error() {
287287 PyList_Insert (traceback_parts, 0 , PyUnicode_FromString (" \n " ));
288288 PyObject* joinstr = PyUnicode_FromString (" " );
289289 PyObject* result = PyUnicode_Join (joinstr, traceback_parts);
290- PyObject* bytes = PyUnicode_AsEncodedString (
291- result, " UTF-8" , " strict"
292- );
293- retv = sass_make_error (PySass_Bytes_AS_STRING (bytes));
290+ retv = PyUnicode_AsEncodedString (result, " UTF-8" , " strict" );
294291 Py_DECREF (traceback_mod);
295292 Py_DECREF (traceback_parts);
296293 Py_DECREF (joinstr);
297294 Py_DECREF (result);
298- Py_DECREF (bytes);
299295 }
300296 Py_DECREF (etype);
301297 Py_DECREF (evalue);
302298 Py_DECREF (etb);
303299 return retv;
304300}
305301
302+ static union Sass_Value* _exception_to_sass_error () {
303+ PyObject* bytes = _exception_to_bytes ();
304+ union Sass_Value* retv = sass_make_error (PySass_Bytes_AS_STRING (bytes));
305+ Py_DECREF (bytes);
306+ return retv;
307+ }
308+
309+ static Sass_Import_List _exception_to_sass_import_error (const char * path) {
310+ PyObject* bytes = _exception_to_bytes ();
311+ Sass_Import_List import_list = sass_make_import_list (1 );
312+ import_list[0 ] = sass_make_import_entry (path, 0 , 0 );
313+ sass_import_set_error (import_list[0 ], PySass_Bytes_AS_STRING (bytes), 0 , 0 );
314+ Py_DECREF (bytes);
315+ return import_list;
316+ }
317+
306318static union Sass_Value* _to_sass_value (PyObject* value) {
307319 union Sass_Value* retv = NULL ;
308320 PyObject* types_mod = PyImport_ImportModule (" sass" );
@@ -404,6 +416,96 @@ static void _add_custom_functions(
404416 sass_option_set_c_functions (options, fn_list);
405417}
406418
419+ static Sass_Import_List _call_py_importer_f (
420+ const char * path, Sass_Importer_Entry cb, struct Sass_Compiler * comp
421+ ) {
422+ PyObject* pyfunc = (PyObject*)sass_importer_get_cookie (cb);
423+ PyObject* py_result = NULL ;
424+ Sass_Import_List sass_imports = NULL ;
425+ Py_ssize_t i;
426+
427+ py_result = PyObject_CallFunction (pyfunc, PySass_IF_PY3 (" y" , " s" ), path);
428+
429+ /* Handle importer throwing an exception */
430+ if (!py_result) goto done;
431+
432+ /* Could return None indicating it could not handle the import */
433+ if (py_result == Py_None) {
434+ Py_XDECREF (py_result);
435+ return NULL ;
436+ }
437+
438+ /* Otherwise, we know our importer is well formed (because we wrap it)
439+ * The return value will be a tuple of 1, 2, or 3 tuples */
440+ sass_imports = sass_make_import_list (PyTuple_GET_SIZE (py_result));
441+ for (i = 0 ; i < PyTuple_GET_SIZE (py_result); i += 1 ) {
442+ char * path_str = NULL ; /* XXX: Memory leak? */
443+ char * source_str = NULL ;
444+ char * sourcemap_str = NULL ;
445+ PyObject* tup = PyTuple_GET_ITEM (py_result, i);
446+ Py_ssize_t size = PyTuple_GET_SIZE (tup);
447+
448+ if (size == 1 ) {
449+ PyArg_ParseTuple (tup, PySass_IF_PY3 (" y" , " s" ), &path_str);
450+ } else if (size == 2 ) {
451+ PyArg_ParseTuple (
452+ tup, PySass_IF_PY3 (" yy" , " ss" ), &path_str, &source_str
453+ );
454+ } else if (size == 3 ) {
455+ PyArg_ParseTuple (
456+ tup, PySass_IF_PY3 (" yyy" , " sss" ),
457+ &path_str, &source_str, &sourcemap_str
458+ );
459+ }
460+
461+ /* We need to give copies of these arguments; libsass handles
462+ * deallocation of them later, whereas path_str is left flapping
463+ * in the breeze -- it's treated const, so that's okay. */
464+ if (source_str) source_str = strdup (source_str);
465+ if (sourcemap_str) sourcemap_str = strdup (sourcemap_str);
466+
467+ sass_imports[i] = sass_make_import_entry (
468+ path_str, source_str, sourcemap_str
469+ );
470+ }
471+
472+ done:
473+ if (sass_imports == NULL ) {
474+ sass_imports = _exception_to_sass_import_error (path);
475+ }
476+
477+ Py_XDECREF (py_result);
478+
479+ return sass_imports;
480+ }
481+
482+ static void _add_custom_importers (
483+ struct Sass_Options * options, PyObject* custom_importers
484+ ) {
485+ Py_ssize_t i;
486+ Sass_Importer_List importer_list;
487+
488+ if (custom_importers == Py_None) {
489+ return ;
490+ }
491+
492+ importer_list = sass_make_importer_list (PyTuple_GET_SIZE (custom_importers));
493+
494+ for (i = 0 ; i < PyTuple_GET_SIZE (custom_importers); i += 1 ) {
495+ PyObject* item = PyTuple_GET_ITEM (custom_importers, i);
496+ int priority = 0 ;
497+ PyObject* import_function = NULL ;
498+
499+ PyArg_ParseTuple (item, " iO" , &priority, &import_function);
500+
501+ importer_list[i] = sass_make_importer (
502+ _call_py_importer_f, priority, import_function
503+ );
504+ }
505+
506+ sass_option_set_c_importers (options, importer_list);
507+ }
508+
407509static PyObject *
408510PySass_compile_string (PyObject *self, PyObject *args) {
409511 struct Sass_Context *ctx;
@@ -414,13 +516,14 @@ PySass_compile_string(PyObject *self, PyObject *args) {
414516 Sass_Output_Style output_style;
415517 int source_comments, error_status, precision, indented;
416518 PyObject *custom_functions;
519+ PyObject *custom_importers;
417520 PyObject *result;
418521
419522 if (!PyArg_ParseTuple (args,
420- PySass_IF_PY3 (" yiiyiOi " , " siisiOi " ),
523+ PySass_IF_PY3 (" yiiyiOiO " , " siisiOiO " ),
421524 &string, &output_style, &source_comments,
422525 &include_paths, &precision,
423- &custom_functions, &indented)) {
526+ &custom_functions, &indented, &custom_importers )) {
424527 return NULL ;
425528 }
426529
@@ -432,7 +535,7 @@ PySass_compile_string(PyObject *self, PyObject *args) {
432535 sass_option_set_precision (options, precision);
433536 sass_option_set_is_indented_syntax_src (options, indented);
434537 _add_custom_functions (options, custom_functions);
435-
538+ _add_custom_importers (options, custom_importers);
436539 sass_compile_data_context (context);
437540
438541 ctx = sass_data_context_get_context (context);
@@ -457,13 +560,15 @@ PySass_compile_filename(PyObject *self, PyObject *args) {
457560 const char *error_message, *output_string, *source_map_string;
458561 Sass_Output_Style output_style;
459562 int source_comments, error_status, precision;
460- PyObject *source_map_filename, *custom_functions, *result;
563+ PyObject *source_map_filename, *custom_functions, *custom_importers,
564+ *result;
461565
462566 if (!PyArg_ParseTuple (args,
463- PySass_IF_PY3 (" yiiyiOO " , " siisiOO " ),
567+ PySass_IF_PY3 (" yiiyiOOO " , " siisiOOO " ),
464568 &filename, &output_style, &source_comments,
465569 &include_paths, &precision,
466- &source_map_filename, &custom_functions)) {
570+ &source_map_filename, &custom_functions,
571+ &custom_importers)) {
467572 return NULL ;
468573 }
469574
@@ -487,7 +592,7 @@ PySass_compile_filename(PyObject *self, PyObject *args) {
487592 sass_option_set_include_path (options, include_paths);
488593 sass_option_set_precision (options, precision);
489594 _add_custom_functions (options, custom_functions);
490-
595+ _add_custom_importers (options, custom_importers);
491596 sass_compile_file_context (context);
492597
493598 ctx = sass_file_context_get_context (context);
0 commit comments