Mercurial > pymonkey
changeset 84:10205d88f6ff
JS-wrapped Python functions can now be passed to context.get_object_private() and context.clear_object_private(), which allows cycles to be manually broken from Python. Far from ideal, but easier than writing a cycle collector for now.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Sun, 09 Aug 2009 15:18:33 -0700 |
parents | ac40f4e03e91 |
children | e9f450d30c0e |
files | context.c test_pymonkey.py |
diffstat | 2 files changed, 62 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/context.c Sun Aug 09 14:47:35 2009 -0700 +++ b/context.c Sun Aug 09 15:18:33 2009 -0700 @@ -118,13 +118,26 @@ if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object)) return NULL; - JSClass *klass = JS_GET_CLASS(self->cx, object->obj); + JSObject *obj = object->obj; + + if (JS_ObjectIsFunction(self->cx, obj)) { + jsval functionHolder; + if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) { + JS_ClearPendingException(self->cx); + Py_RETURN_NONE; + } + if (!JSVAL_IS_OBJECT(functionHolder)) + Py_RETURN_NONE; + obj = JSVAL_TO_OBJECT(functionHolder); + } + + JSClass *klass = JS_GET_CLASS(self->cx, obj); if (klass != &PYM_JS_ObjectClass) Py_RETURN_NONE; PyObject *pyObject; - if (!PYM_JS_getPrivatePyObject(self->cx, object->obj, &pyObject)) { + if (!PYM_JS_getPrivatePyObject(self->cx, obj, &pyObject)) { PYM_jsExceptionToPython(self); return NULL; } @@ -144,11 +157,24 @@ if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object)) return NULL; - JSClass *klass = JS_GET_CLASS(self->cx, object->obj); + JSObject *obj = object->obj; + + if (JS_ObjectIsFunction(self->cx, obj)) { + jsval functionHolder; + if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) { + JS_ClearPendingException(self->cx); + Py_RETURN_NONE; + } + if (!JSVAL_IS_OBJECT(functionHolder)) + Py_RETURN_NONE; + obj = JSVAL_TO_OBJECT(functionHolder); + } + + JSClass *klass = JS_GET_CLASS(self->cx, obj); if (klass != &PYM_JS_ObjectClass) Py_RETURN_NONE; - if (!PYM_JS_setPrivatePyObject(self->cx, object->obj, Py_None)) { + if (!PYM_JS_setPrivatePyObject(self->cx, obj, Py_None)) { PYM_jsExceptionToPython(self); return NULL; }
--- a/test_pymonkey.py Sun Aug 09 14:47:35 2009 -0700 +++ b/test_pymonkey.py Sun Aug 09 15:18:33 2009 -0700 @@ -81,6 +81,14 @@ self.assertEqual(str(pymonkey.undefined), "pymonkey.undefined") + def testJsWrappedPythonFuncHasPrivate(self): + def foo(cx, this, args): + pass + + cx = pymonkey.Runtime().new_context() + jsfunc = cx.new_function(foo, foo.__name__) + self.assertEqual(cx.get_object_private(jsfunc), foo) + def testJsWrappedPythonFuncIsNotGCd(self): def define(cx, obj): def func(cx, this, args): @@ -104,6 +112,30 @@ cx.gc() self.assertEqual(ref(), None) + def testCircularJsWrappedPythonFuncIsGCdIfPrivateCleared(self): + def define(cx, obj): + rt = cx.get_runtime() + def func(cx, this, args): + # Oh noes, a circular reference is born! + rt + jsfunc = cx.new_function(func, func.__name__) + cx.define_property(obj, func.__name__, jsfunc) + return (jsfunc, weakref.ref(func)) + rt = pymonkey.Runtime() + cx = rt.new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc, ref = define(cx, obj) + + # This will break the circular reference. + cx.clear_object_private(jsfunc) + + del jsfunc + del rt + del cx + del obj + self.assertEqual(ref(), None) + def testJsWrappedPythonFuncIsGCdAtRuntimeDestruction(self): def define(cx, obj): def func(cx, this, args):