mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Update duktape python bindings
This commit is contained in:
parent
2368db92d6
commit
5d3d892923
@ -18,6 +18,7 @@ static int DukContext_init(DukContext *self, PyObject *args, PyObject *kw)
|
|||||||
(void)kw;
|
(void)kw;
|
||||||
|
|
||||||
self->heap_manager = NULL; /* We manage the heap */
|
self->heap_manager = NULL; /* We manage the heap */
|
||||||
|
self->py_thread_state = NULL;
|
||||||
|
|
||||||
self->ctx = duk_create_heap_default();
|
self->ctx = duk_create_heap_default();
|
||||||
if (!self->ctx) {
|
if (!self->ctx) {
|
||||||
@ -87,7 +88,7 @@ static void DukContext_dealloc(DukContext *self)
|
|||||||
static PyObject *DukContext_eval(DukContext *self, PyObject *args, PyObject *kw)
|
static PyObject *DukContext_eval(DukContext *self, PyObject *args, PyObject *kw)
|
||||||
{
|
{
|
||||||
const char *code;
|
const char *code;
|
||||||
int noresult = 0;
|
int noresult = 0, ret = 0;
|
||||||
PyObject *result = NULL, *temp = NULL;
|
PyObject *result = NULL, *temp = NULL;
|
||||||
|
|
||||||
static char *keywords[] = {"code", "noreturn", NULL};
|
static char *keywords[] = {"code", "noreturn", NULL};
|
||||||
@ -97,7 +98,11 @@ static PyObject *DukContext_eval(DukContext *self, PyObject *args, PyObject *kw)
|
|||||||
}
|
}
|
||||||
if (temp && PyObject_IsTrue(temp)) noresult = 1;
|
if (temp && PyObject_IsTrue(temp)) noresult = 1;
|
||||||
|
|
||||||
if (duk_peval_string(self->ctx, code) != 0) {
|
self->py_thread_state = PyEval_SaveThread(); // Release GIL
|
||||||
|
ret = duk_peval_string(self->ctx, code);
|
||||||
|
PyEval_RestoreThread(self->py_thread_state); // Acquire GIL
|
||||||
|
self->py_thread_state = NULL;
|
||||||
|
if (ret != 0) {
|
||||||
temp = duk_to_python(self->ctx, -1);
|
temp = duk_to_python(self->ctx, -1);
|
||||||
if (temp) {
|
if (temp) {
|
||||||
PyErr_SetObject(JSError, temp);
|
PyErr_SetObject(JSError, temp);
|
||||||
@ -121,7 +126,7 @@ static PyObject *DukContext_eval(DukContext *self, PyObject *args, PyObject *kw)
|
|||||||
static PyObject *DukContext_eval_file(DukContext *self, PyObject *args, PyObject *kw)
|
static PyObject *DukContext_eval_file(DukContext *self, PyObject *args, PyObject *kw)
|
||||||
{
|
{
|
||||||
const char *path;
|
const char *path;
|
||||||
int noresult = 0;
|
int noresult = 0, ret = 0;
|
||||||
PyObject *result = NULL, *temp = NULL;
|
PyObject *result = NULL, *temp = NULL;
|
||||||
|
|
||||||
static char *keywords[] = {"path", "noreturn", NULL};
|
static char *keywords[] = {"path", "noreturn", NULL};
|
||||||
@ -131,7 +136,11 @@ static PyObject *DukContext_eval_file(DukContext *self, PyObject *args, PyObject
|
|||||||
}
|
}
|
||||||
if (temp && PyObject_IsTrue(temp)) noresult = 1;
|
if (temp && PyObject_IsTrue(temp)) noresult = 1;
|
||||||
|
|
||||||
if (duk_peval_file(self->ctx, path) != 0) {
|
self->py_thread_state = PyEval_SaveThread(); // Release GIL
|
||||||
|
ret = duk_peval_file(self->ctx, path);
|
||||||
|
PyEval_RestoreThread(self->py_thread_state); // Acquire GIL
|
||||||
|
self->py_thread_state = NULL;
|
||||||
|
if (ret != 0) {
|
||||||
temp = duk_to_python(self->ctx, -1);
|
temp = duk_to_python(self->ctx, -1);
|
||||||
if (temp) {
|
if (temp) {
|
||||||
PyErr_SetObject(JSError, temp);
|
PyErr_SetObject(JSError, temp);
|
||||||
|
@ -20,53 +20,95 @@ static int get_repr(PyObject *value, char *buf, int bufsz) {
|
|||||||
static duk_ret_t python_function_caller(duk_context *ctx)
|
static duk_ret_t python_function_caller(duk_context *ctx)
|
||||||
{
|
{
|
||||||
PyObject *func, *args, *result;
|
PyObject *func, *args, *result;
|
||||||
|
DukContext *dctx;
|
||||||
duk_idx_t nargs, i;
|
duk_idx_t nargs, i;
|
||||||
static char buf1[200], buf2[1024];
|
static char buf1[200], buf2[1024];
|
||||||
|
int gil_acquired = 0, ret = 1;
|
||||||
|
|
||||||
|
dctx = DukContext_get(ctx);
|
||||||
nargs = duk_get_top(ctx);
|
nargs = duk_get_top(ctx);
|
||||||
|
|
||||||
duk_push_current_function(ctx);
|
duk_push_current_function(ctx);
|
||||||
duk_get_prop_string(ctx, -1, "\xff" "py_object");
|
duk_get_prop_string(ctx, -1, "\xff" "py_object");
|
||||||
func = duk_get_pointer(ctx, -1);
|
func = duk_get_pointer(ctx, -1);
|
||||||
|
|
||||||
|
if (dctx->py_thread_state) {
|
||||||
|
gil_acquired = 1;
|
||||||
|
PyEval_RestoreThread(dctx->py_thread_state);
|
||||||
|
dctx->py_thread_state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
args = PyTuple_New(nargs);
|
args = PyTuple_New(nargs);
|
||||||
if (!args)
|
if (!args) {
|
||||||
return DUK_RET_ALLOC_ERROR;
|
ret = DUK_RET_ALLOC_ERROR;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < nargs; i++) {
|
for (i = 0; i < nargs; i++) {
|
||||||
PyObject *arg = duk_to_python(ctx, i);
|
PyObject *arg = duk_to_python(ctx, i);
|
||||||
if (arg == NULL)
|
if (arg == NULL) {
|
||||||
return DUK_RET_TYPE_ERROR;
|
Py_DECREF(args);
|
||||||
|
ret = DUK_RET_TYPE_ERROR;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
PyTuple_SET_ITEM(args, i, arg);
|
PyTuple_SET_ITEM(args, i, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = PyObject_Call(func, args, NULL);
|
result = PyObject_Call(func, args, NULL);
|
||||||
|
Py_DECREF(args);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
get_repr(func, buf1, 200);
|
get_repr(func, buf1, 200);
|
||||||
if (!PyErr_Occurred())
|
if (!PyErr_Occurred()) {
|
||||||
|
if (gil_acquired) {
|
||||||
|
dctx->py_thread_state = PyEval_SaveThread();
|
||||||
|
gil_acquired = 0;
|
||||||
|
}
|
||||||
duk_error(ctx, DUK_ERR_ERROR, "Python function (%s) failed", buf1);
|
duk_error(ctx, DUK_ERR_ERROR, "Python function (%s) failed", buf1);
|
||||||
|
}
|
||||||
PyObject *ptype = NULL, *pval = NULL, *tb = NULL;
|
PyObject *ptype = NULL, *pval = NULL, *tb = NULL;
|
||||||
PyErr_Fetch(&ptype, &pval, &tb);
|
PyErr_Fetch(&ptype, &pval, &tb);
|
||||||
if (!get_repr(pval, buf2, 1024)) get_repr(ptype, buf2, 1024);
|
if (!get_repr(pval, buf2, 1024)) get_repr(ptype, buf2, 1024);
|
||||||
Py_XDECREF(ptype); Py_XDECREF(pval); Py_XDECREF(tb);
|
Py_XDECREF(ptype); Py_XDECREF(pval); Py_XDECREF(tb);
|
||||||
PyErr_Clear(); /* In case there was an error in get_repr() */
|
PyErr_Clear(); /* In case there was an error in get_repr() */
|
||||||
|
if (gil_acquired) {
|
||||||
|
dctx->py_thread_state = PyEval_SaveThread();
|
||||||
|
gil_acquired = 0;
|
||||||
|
}
|
||||||
duk_error(ctx, DUK_ERR_ERROR, "Python function (%s) failed with error: %s", buf1, buf2);
|
duk_error(ctx, DUK_ERR_ERROR, "Python function (%s) failed with error: %s", buf1, buf2);
|
||||||
|
|
||||||
}
|
}
|
||||||
python_to_duk(ctx, result);
|
python_to_duk(ctx, result);
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return 1;
|
error:
|
||||||
|
if (gil_acquired) {
|
||||||
|
dctx->py_thread_state = PyEval_SaveThread();
|
||||||
|
gil_acquired = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static duk_ret_t python_object_decref(duk_context *ctx) {
|
static duk_ret_t python_object_decref(duk_context *ctx) {
|
||||||
int deleted = 0;
|
int deleted = 0, gil_acquired = 0;
|
||||||
|
DukContext *dctx = DukContext_get(ctx);
|
||||||
|
|
||||||
|
|
||||||
duk_get_prop_string(ctx, 0, "\xff""deleted");
|
duk_get_prop_string(ctx, 0, "\xff""deleted");
|
||||||
deleted = duk_to_boolean(ctx, -1);
|
deleted = duk_to_boolean(ctx, -1);
|
||||||
duk_pop(ctx);
|
duk_pop(ctx);
|
||||||
if (!deleted) {
|
if (!deleted) {
|
||||||
duk_get_prop_string(ctx, 0, "\xff""py_object");
|
duk_get_prop_string(ctx, 0, "\xff""py_object");
|
||||||
|
if (dctx->py_thread_state) {
|
||||||
|
gil_acquired = 1;
|
||||||
|
PyEval_RestoreThread(dctx->py_thread_state);
|
||||||
|
dctx->py_thread_state = NULL;
|
||||||
|
}
|
||||||
Py_XDECREF(duk_get_pointer(ctx, -1));
|
Py_XDECREF(duk_get_pointer(ctx, -1));
|
||||||
|
if (gil_acquired) {
|
||||||
|
dctx->py_thread_state = PyEval_SaveThread();
|
||||||
|
gil_acquired = 0;
|
||||||
|
}
|
||||||
duk_pop(ctx);
|
duk_pop(ctx);
|
||||||
|
|
||||||
// Mark as deleted
|
// Mark as deleted
|
||||||
|
@ -22,6 +22,7 @@ struct DukContext_ {
|
|||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
duk_context *ctx;
|
duk_context *ctx;
|
||||||
DukContext *heap_manager;
|
DukContext *heap_manager;
|
||||||
|
PyThreadState *py_thread_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
PyTypeObject DukContext_Type;
|
PyTypeObject DukContext_Type;
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
from threading import Thread, Event
|
||||||
from duktape import dukpy
|
from duktape import dukpy
|
||||||
undefined, JSError, Context = dukpy.undefined, dukpy.JSError, dukpy.Context
|
undefined, JSError, Context = dukpy.undefined, dukpy.JSError, dukpy.Context
|
||||||
|
|
||||||
class ContextTests(unittest.TestCase):
|
class ContextTests(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.ctx = Context()
|
self.ctx = Context()
|
||||||
self.g = self.ctx.g
|
self.g = self.ctx.g
|
||||||
@ -30,6 +32,7 @@ class ContextTests(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class ValueTests(unittest.TestCase):
|
class ValueTests(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.ctx = Context()
|
self.ctx = Context()
|
||||||
self.g = self.ctx.g
|
self.g = self.ctx.g
|
||||||
@ -106,6 +109,7 @@ class ValueTests(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class EvalTests(unittest.TestCase):
|
class EvalTests(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.ctx = Context()
|
self.ctx = Context()
|
||||||
self.g = self.ctx.g
|
self.g = self.ctx.g
|
||||||
@ -148,6 +152,18 @@ class EvalTests(unittest.TestCase):
|
|||||||
self.assertEqual('ReferenceError', e.name)
|
self.assertEqual('ReferenceError', e.name)
|
||||||
self.assertEqual(2, e.lineNumber)
|
self.assertEqual(2, e.lineNumber)
|
||||||
|
|
||||||
|
def test_eval_multithreading(self):
|
||||||
|
ev = Event()
|
||||||
|
self.ctx.g.func = ev.wait
|
||||||
|
t = Thread(target=self.ctx.eval, args=('func()',))
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
t.join(0.01)
|
||||||
|
self.assertTrue(t.is_alive())
|
||||||
|
ev.set()
|
||||||
|
t.join(1)
|
||||||
|
self.assertFalse(t.is_alive())
|
||||||
|
|
||||||
def test_eval_noreturn(self):
|
def test_eval_noreturn(self):
|
||||||
self.assertIsNone(self.ctx.eval("1+1", noreturn=True))
|
self.assertIsNone(self.ctx.eval("1+1", noreturn=True))
|
||||||
|
|
||||||
@ -166,5 +182,3 @@ class EvalTests(unittest.TestCase):
|
|||||||
|
|
||||||
def test_eval_file_noreturn(self):
|
def test_eval_file_noreturn(self):
|
||||||
self.assertIsNone(self.ctx.eval_file(self.testfile, noreturn=True))
|
self.assertIsNone(self.ctx.eval_file(self.testfile, noreturn=True))
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user