@@ -42,6 +42,7 @@ static const char *exc_to_str(void)
4242
4343struct NativeCtx {
4444 struct JsonnetVm * vm ;
45+ PyThreadState * * py_thread ;
4546 PyObject * callback ;
4647 size_t argc ;
4748};
@@ -139,6 +140,8 @@ static struct JsonnetJsonValue *cpython_native_callback(
139140 const struct NativeCtx * ctx = ctx_ ;
140141 int i ;
141142
143+ PyEval_RestoreThread (* ctx -> py_thread );
144+
142145 PyObject * arglist ; // Will hold a tuple of strings.
143146 PyObject * result ; // Will hold a string.
144147
@@ -168,6 +171,7 @@ static struct JsonnetJsonValue *cpython_native_callback(
168171 // TODO(dcunnin): Support objects (to dicts).
169172 Py_DECREF (arglist );
170173 * succ = 0 ;
174+ * ctx -> py_thread = PyEval_SaveThread ();
171175 return jsonnet_json_make_string (ctx -> vm , "Non-primitive param." );
172176 }
173177 PyTuple_SetItem (arglist , i , pyobj );
@@ -182,6 +186,7 @@ static struct JsonnetJsonValue *cpython_native_callback(
182186 struct JsonnetJsonValue * r = jsonnet_json_make_string (ctx -> vm , exc_to_str ());
183187 * succ = 0 ;
184188 PyErr_Clear ();
189+ * ctx -> py_thread = PyEval_SaveThread ();
185190 return r ;
186191 }
187192
@@ -193,12 +198,14 @@ static struct JsonnetJsonValue *cpython_native_callback(
193198 * succ = 0 ;
194199 r = jsonnet_json_make_string (ctx -> vm , err_msg );
195200 }
201+ * ctx -> py_thread = PyEval_SaveThread ();
196202 return r ;
197203}
198204
199205
200206struct ImportCtx {
201207 struct JsonnetVm * vm ;
208+ PyThreadState * * py_thread ;
202209 PyObject * callback ;
203210};
204211
@@ -209,6 +216,7 @@ static char *cpython_import_callback(void *ctx_, const char *base, const char *r
209216 PyObject * arglist , * result ;
210217 char * out ;
211218
219+ PyEval_RestoreThread (* ctx -> py_thread );
212220 arglist = Py_BuildValue ("(s, s)" , base , rel );
213221 result = PyEval_CallObject (ctx -> callback , arglist );
214222 Py_DECREF (arglist );
@@ -218,6 +226,7 @@ static char *cpython_import_callback(void *ctx_, const char *base, const char *r
218226 char * out = jsonnet_str (ctx -> vm , exc_to_str ());
219227 * success = 0 ;
220228 PyErr_Clear ();
229+ * ctx -> py_thread = PyEval_SaveThread ();
221230 return out ;
222231 }
223232
@@ -252,6 +261,7 @@ static char *cpython_import_callback(void *ctx_, const char *base, const char *r
252261 }
253262
254263 Py_DECREF (result );
264+ * ctx -> py_thread = PyEval_SaveThread ();
255265
256266 return out ;
257267}
@@ -340,7 +350,7 @@ int handle_import_callback(struct ImportCtx *ctx, PyObject *import_callback)
340350 * \returns 1 on success, 0 with exception set upon failure.
341351 */
342352static int handle_native_callbacks (struct JsonnetVm * vm , PyObject * native_callbacks ,
343- struct NativeCtx * * ctxs )
353+ struct NativeCtx * * ctxs , PyThreadState * * py_thread )
344354{
345355 size_t num_natives = 0 ;
346356 PyObject * key , * val ;
@@ -433,6 +443,7 @@ static int handle_native_callbacks(struct JsonnetVm *vm, PyObject *native_callba
433443 }
434444 params_c [num_params ] = NULL ;
435445 (* ctxs )[num_natives ].vm = vm ;
446+ (* ctxs )[num_natives ].py_thread = py_thread ;
436447 (* ctxs )[num_natives ].callback = PyTuple_GetItem (val , 1 );
437448 (* ctxs )[num_natives ].argc = num_params ;
438449 jsonnet_native_callback (vm , key_ , cpython_native_callback , & (* ctxs )[num_natives ],
@@ -448,11 +459,12 @@ static int handle_native_callbacks(struct JsonnetVm *vm, PyObject *native_callba
448459static PyObject * evaluate_file (PyObject * self , PyObject * args , PyObject * keywds )
449460{
450461 const char * filename ;
451- const char * jpathdir = NULL ;
452- char * out ;
462+ char * out , * jpath_str ;
453463 unsigned max_stack = 500 , gc_min_objects = 1000 , max_trace = 20 ;
454464 double gc_growth_trigger = 2 ;
455465 int error ;
466+ Py_ssize_t num_jpathdir , i ;
467+ PyObject * jpathdir = NULL ;
456468 PyObject * ext_vars = NULL , * ext_codes = NULL ;
457469 PyObject * tla_vars = NULL , * tla_codes = NULL ;
458470 PyObject * import_callback = NULL ;
@@ -469,47 +481,79 @@ static PyObject* evaluate_file(PyObject* self, PyObject* args, PyObject *keywds)
469481 (void ) self ;
470482
471483 if (!PyArg_ParseTupleAndKeywords (
472- args , keywds , "s|sIIdOOOOIOO " , kwlist ,
484+ args , keywds , "s|OIIdOOOOIOO " , kwlist ,
473485 & filename , & jpathdir ,
474486 & max_stack , & gc_min_objects , & gc_growth_trigger , & ext_vars ,
475487 & ext_codes , & tla_vars , & tla_codes , & max_trace , & import_callback ,
476488 & native_callbacks )) {
477489 return NULL ;
478490 }
479491
492+ PyThreadState * py_thread ;
493+
480494 vm = jsonnet_make ();
481495 jsonnet_max_stack (vm , max_stack );
482496 jsonnet_gc_min_objects (vm , gc_min_objects );
483497 jsonnet_max_trace (vm , max_trace );
484498 jsonnet_gc_growth_trigger (vm , gc_growth_trigger );
485- if (jpathdir != NULL )
486- jsonnet_jpath_add (vm , jpathdir );
499+
500+ if (jpathdir != NULL ) {
501+ // Support string for backward compatibility with <= 0.15.0
502+ #if PY_MAJOR_VERSION >= 3
503+ if (PyUnicode_Check (jpathdir )) {
504+ jpath_str = PyUnicode_AsUTF8 (jpathdir );
505+ #else
506+ if (PyString_Check (jpathdir )) {
507+ jpath_str = PyString_AsString (jpathdir );
508+ #endif
509+ jsonnet_jpath_add (vm , jpath_str );
510+ } else if (PyList_Check (jpathdir )) {
511+ num_jpathdir = PyList_Size (jpathdir );
512+ for (i = 0 ; i < num_jpathdir ; ++ i ) {
513+ PyObject * jpath = PyList_GetItem (jpathdir , i );
514+ #if PY_MAJOR_VERSION >= 3
515+ if (PyUnicode_Check (jpath )) {
516+ jpath_str = PyUnicode_AsUTF8 (jpath );
517+ #else
518+ if (PyString_Check (jpath )) {
519+ jpath_str = PyString_AsString (jpath );
520+ #endif
521+ jsonnet_jpath_add (vm , jpath_str );
522+ }
523+ }
524+ }
525+ }
526+
487527 if (!handle_vars (vm , ext_vars , 0 , 0 )) return NULL ;
488528 if (!handle_vars (vm , ext_codes , 1 , 0 )) return NULL ;
489529 if (!handle_vars (vm , tla_vars , 0 , 1 )) return NULL ;
490530 if (!handle_vars (vm , tla_codes , 1 , 1 )) return NULL ;
491- struct ImportCtx ctx = { vm , import_callback };
531+
532+ struct ImportCtx ctx = { vm , & py_thread , import_callback };
492533 if (!handle_import_callback (& ctx , import_callback )) {
493534 return NULL ;
494535 }
495536 struct NativeCtx * ctxs = NULL ;
496- if (!handle_native_callbacks (vm , native_callbacks , & ctxs )) {
537+ if (!handle_native_callbacks (vm , native_callbacks , & ctxs , & py_thread )) {
497538 free (ctxs );
498539 return NULL ;
499540 }
541+ py_thread = PyEval_SaveThread ();
500542 out = jsonnet_evaluate_file (vm , filename , & error );
543+ PyEval_RestoreThread (py_thread );
501544 free (ctxs );
502545 return handle_result (vm , out , error );
503546}
504547
505548static PyObject * evaluate_snippet (PyObject * self , PyObject * args , PyObject * keywds )
506549{
507550 const char * filename , * src ;
508- const char * jpathdir = NULL ;
509- char * out ;
551+ char * out , * jpath_str ;
510552 unsigned max_stack = 500 , gc_min_objects = 1000 , max_trace = 20 ;
511553 double gc_growth_trigger = 2 ;
512554 int error ;
555+ Py_ssize_t num_jpathdir , i ;
556+ PyObject * jpathdir = NULL ;
513557 PyObject * ext_vars = NULL , * ext_codes = NULL ;
514558 PyObject * tla_vars = NULL , * tla_codes = NULL ;
515559 PyObject * import_callback = NULL ;
@@ -526,35 +570,65 @@ static PyObject* evaluate_snippet(PyObject* self, PyObject* args, PyObject *keyw
526570 (void ) self ;
527571
528572 if (!PyArg_ParseTupleAndKeywords (
529- args , keywds , "ss|sIIdOOOOIOO " , kwlist ,
573+ args , keywds , "ss|OIIdOOOOIOO " , kwlist ,
530574 & filename , & src , & jpathdir ,
531575 & max_stack , & gc_min_objects , & gc_growth_trigger , & ext_vars ,
532576 & ext_codes , & tla_vars , & tla_codes , & max_trace , & import_callback ,
533577 & native_callbacks )) {
534578 return NULL ;
535579 }
536580
581+ PyThreadState * py_thread ;
582+
537583 vm = jsonnet_make ();
538584 jsonnet_max_stack (vm , max_stack );
539585 jsonnet_gc_min_objects (vm , gc_min_objects );
540586 jsonnet_max_trace (vm , max_trace );
541587 jsonnet_gc_growth_trigger (vm , gc_growth_trigger );
542- if (jpathdir != NULL )
543- jsonnet_jpath_add (vm , jpathdir );
588+
589+ if (jpathdir != NULL ) {
590+ // Support string for backward compatibility with <= 0.15.0
591+ #if PY_MAJOR_VERSION >= 3
592+ if (PyUnicode_Check (jpathdir )) {
593+ jpath_str = PyUnicode_AsUTF8 (jpathdir );
594+ #else
595+ if (PyString_Check (jpathdir )) {
596+ jpath_str = PyString_AsString (jpathdir );
597+ #endif
598+ jsonnet_jpath_add (vm , jpath_str );
599+ } else if (PyList_Check (jpathdir )) {
600+ num_jpathdir = PyList_Size (jpathdir );
601+ for (i = 0 ; i < num_jpathdir ; ++ i ) {
602+ PyObject * jpath = PyList_GetItem (jpathdir , i );
603+ #if PY_MAJOR_VERSION >= 3
604+ if (PyUnicode_Check (jpath )) {
605+ jpath_str = PyUnicode_AsUTF8 (jpath );
606+ #else
607+ if (PyString_Check (jpath )) {
608+ jpath_str = PyString_AsString (jpath );
609+ #endif
610+ jsonnet_jpath_add (vm , jpath_str );
611+ }
612+ }
613+ }
614+ }
615+
544616 if (!handle_vars (vm , ext_vars , 0 , 0 )) return NULL ;
545617 if (!handle_vars (vm , ext_codes , 1 , 0 )) return NULL ;
546618 if (!handle_vars (vm , tla_vars , 0 , 1 )) return NULL ;
547619 if (!handle_vars (vm , tla_codes , 1 , 1 )) return NULL ;
548- struct ImportCtx ctx = { vm , import_callback };
620+ struct ImportCtx ctx = { vm , & py_thread , import_callback };
549621 if (!handle_import_callback (& ctx , import_callback )) {
550622 return NULL ;
551623 }
552624 struct NativeCtx * ctxs = NULL ;
553- if (!handle_native_callbacks (vm , native_callbacks , & ctxs )) {
625+ if (!handle_native_callbacks (vm , native_callbacks , & ctxs , & py_thread )) {
554626 free (ctxs );
555627 return NULL ;
556628 }
629+ py_thread = PyEval_SaveThread ();
557630 out = jsonnet_evaluate_snippet (vm , filename , src , & error );
631+ PyEval_RestoreThread (py_thread );
558632 free (ctxs );
559633 return handle_result (vm , out , error );
560634}
0 commit comments