Mercurial > pymonkey
changeset 64:fb7e11dec538
Added context.set_operation_callback() and trigger_operation_callback() methods.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Sun, 26 Jul 2009 12:43:31 -0700 |
parents | f3ecf06a2851 |
children | f89a582c1276 |
files | context.c context.h test_pymonkey.py |
diffstat | 3 files changed, 90 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/context.c Sat Jul 25 23:08:47 2009 -0700 +++ b/context.c Sun Jul 26 12:43:31 2009 -0700 @@ -39,6 +39,29 @@ #include "function.h" #include "utils.h" +static JSBool +PYM_operationCallback(JSContext *cx) +{ + PYM_JSContextObject *context = (PYM_JSContextObject *) + JS_GetContextPrivate(cx); + + PyObject *callable = context->opCallback; + PyObject *args = PyTuple_Pack(1, (PyObject *) context); + if (args == NULL) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + PyObject *result = PyObject_Call(callable, args, NULL); + Py_DECREF(args); + if (result == NULL) { + PYM_pythonExceptionToJs(context); + return JS_FALSE; + } + + Py_DECREF(result); + return JS_TRUE; +} + // This is the default JSErrorReporter for pymonkey-owned JS contexts. static void PYM_reportError(JSContext *cx, const char *message, JSErrorReport *report) @@ -59,6 +82,11 @@ static void PYM_JSContextDealloc(PYM_JSContextObject *self) { + if (self->opCallback) { + Py_DECREF(self->opCallback); + self->opCallback = NULL; + } + if (self->cx) { JS_DestroyContext(self->cx); self->cx = NULL; @@ -259,6 +287,36 @@ return (PyObject *) PYM_newJSFunctionFromCallable(self, callable, name); } +static PyObject * +PYM_setOperationCallback(PYM_JSContextObject *self, PyObject *args) +{ + PyObject *callable; + + if (!PyArg_ParseTuple(args, "O", &callable)) + return NULL; + + if (!PyCallable_Check(callable)) { + PyErr_SetString(PyExc_TypeError, "Callable must be callable"); + return NULL; + } + + JS_SetOperationCallback(self->cx, PYM_operationCallback); + + Py_INCREF(callable); + if (self->opCallback) + Py_DECREF(self->opCallback); + self->opCallback = callable; + + Py_RETURN_NONE; +} + +static PyObject * +PYM_triggerOperationCallback(PYM_JSContextObject *self, PyObject *args) +{ + JS_TriggerOperationCallback(self->cx); + Py_RETURN_NONE; +} + static PyMethodDef PYM_JSContextMethods[] = { {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS, "Get the JavaScript runtime associated with this context."}, @@ -285,6 +343,12 @@ "Gets the given property for the given JavaScript object."}, {"gc", (PyCFunction) PYM_gc, METH_VARARGS, "Performs garbage collection on the context's runtime."}, + {"set_operation_callback", (PyCFunction) PYM_setOperationCallback, + METH_VARARGS, + "Sets the operation callback for the context."}, + {"trigger_operation_callback", (PyCFunction) PYM_triggerOperationCallback, + METH_VARARGS, + "Triggers the operation callback for the context."}, {NULL, NULL, 0, NULL} }; @@ -340,6 +404,7 @@ if (context == NULL) return NULL; + context->opCallback = NULL; context->runtime = runtime; Py_INCREF(runtime);
--- a/context.h Sat Jul 25 23:08:47 2009 -0700 +++ b/context.h Sun Jul 26 12:43:31 2009 -0700 @@ -46,6 +46,7 @@ PyObject_HEAD PYM_JSRuntimeObject *runtime; JSContext *cx; + PyObject *opCallback; } PYM_JSContextObject; extern PyTypeObject PYM_JSContextType;
--- a/test_pymonkey.py Sat Jul 25 23:08:47 2009 -0700 +++ b/test_pymonkey.py Sun Jul 26 12:43:31 2009 -0700 @@ -29,6 +29,30 @@ was_raised = True self.assertTrue(was_raised) + def testOperationCallbackIsCalled(self): + def opcb(cx): + raise Exception("stop eet!") + + cx = pymonkey.Runtime().new_context() + cx.set_operation_callback(opcb) + obj = cx.new_object() + cx.init_standard_classes(obj) + + # TODO: This isn't a very good test; we need to actually + # set up a signal or launch a separate thread to call + # this method as though it were a watchdog to limit the + # amount of time the JS can run. However, Pymonkey doesn't + # yet handle the GIL properly so this isn't possible. + cx.trigger_operation_callback() + + self.assertRaises( + pymonkey.error, + cx.evaluate_script, + obj, 'while (1) {}', '<string>', 1 + ) + self.assertEqual(self.last_exception.message, + "stop eet!") + def testUndefinedStrIsUndefined(self): self.assertEqual(str(pymonkey.undefined), "pymonkey.undefined")