# HG changeset patch # User Atul Varma # Date 1252323524 25200 # Node ID 69e5523ebdc6863fa8d5d2038ddc4ae83ff69f83 # Parent 1d62177c5c2706296a4c2e46de5f36a727cac7c6 Separated out SafeJsObjectWrapper into itself and a new subclass, SafeJsFunctionWrapper, so that callable() works properly on instances. diff -r 1d62177c5c27 -r 69e5523ebdc6 pydershell/pydershell.py --- a/pydershell/pydershell.py Mon Sep 07 04:23:09 2009 -0700 +++ b/pydershell/pydershell.py Mon Sep 07 04:38:44 2009 -0700 @@ -81,29 +81,23 @@ object.__setattr__(self, '_cx', cx) object.__setattr__(self, '_this', this) - def __wrap_to_python(self, value): - if isinstance(value, pydermonkey.Object): - return SafeJsObjectWrapper(self._cx, value, self._jsobject) + @staticmethod + def wrap(cx, jsvalue, this): + if isinstance(jsvalue, pydermonkey.Function): + return SafeJsFunctionWrapper(cx, jsvalue, this) + elif isinstance(jsvalue, pydermonkey.Object): + return SafeJsObjectWrapper(cx, jsvalue, this) else: - return value + # It's a primitive value. + return jsvalue - def __wrap_to_js(self, value): + def _wrap_to_python(self, jsvalue): + return self.wrap(self._cx, jsvalue, self._jsobject) + + def _wrap_to_js(self, value): # TODO: Add support for wrapping non-primitive python objects. return value - def __call__(self, *args): - cx = self._cx - jsobject = self._jsobject - this = self._this - - if isinstance(jsobject, pydermonkey.Function): - obj = cx.call_function(this, jsobject, - self.__wrap_to_js(args)) - return self.__wrap_to_python(obj) - else: - raise TypeError("'%s' object is not callable" % - type(jsobject).__name__) - def __eq__(self, other): if isinstance(other, SafeJsObjectWrapper): return self._jsobject == other._jsobject @@ -124,7 +118,7 @@ jsobject = self._jsobject cx.define_property(jsobject, name, - self.__wrap_to_js(value)) + self._wrap_to_js(value)) def __getitem__(self, item): return self.__getattr__(item) @@ -133,7 +127,7 @@ cx = self._cx jsobject = self._jsobject - return self.__wrap_to_python(cx.get_property(jsobject, name)) + return self._wrap_to_python(cx.get_property(jsobject, name)) def __contains__(self, item): cx = self._cx @@ -149,6 +143,26 @@ for property in properties: yield property +class SafeJsFunctionWrapper(SafeJsObjectWrapper): + """ + Securely wraps a JS function to behave like any normal Python object. + """ + + def __init__(self, cx, jsfunction, this): + if not isinstance(jsfunction, pydermonkey.Function): + raise TypeError("Cannot wrap '%s' object" % + type(jsobject).__name__) + SafeJsObjectWrapper.__init__(self, cx, jsfunction, this) + + def __call__(self, *args): + cx = self._cx + jsobject = self._jsobject + this = self._this + + obj = cx.call_function(this, jsobject, + self._wrap_to_js(args)) + return self._wrap_to_python(obj) + def safejsfunc(cx, on_obj, name=None): """ Exposes the decorated Python function on the given JS object. @@ -224,7 +238,7 @@ @safejsfunc(cx, globalobj) def bar(cx, this, args): - obj = SafeJsObjectWrapper(cx, args[0], this) + obj = SafeJsObjectWrapper.wrap(cx, args[0], this) print obj.bar() @safejsfunc(cx, globalobj)