Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion dcp/dry/class_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ def js_ref_generator(self, *args, **kwargs):
# otherwise, instantiate a new underlying js ref using the ctor args
else:
async_wrapped_ctor = blockify(pm.new(js_class))
self.js_ref = async_wrapped_ctor(*args, **kwargs)
# If constructor takes other BF2 objects, the underlying JS proxy must be passed instead
unwrapped_args = tuple(arg.js_ref if hasattr(arg, 'js_ref') else arg for arg in args)
self.js_ref = async_wrapped_ctor(*unwrapped_args, **kwargs)
Comment thread
YarnSaw marked this conversation as resolved.
return self.js_ref

return make_new_class(js_ref_generator, name, js_class=js_class)
Expand All @@ -120,6 +122,10 @@ def wrap_obj(js_val):
bfclass = reg.add(bfclass)

return bfclass(js_val)

# TODO: Arrays from bf2 objects are returned UNWRAPPED as pm.JSArrayProxy
# TODO: This causes errors when you call an async function within an array
# TODO: To solve this we likely have to write a bf2 array wrapper?
return js_val

# TODO: there must be a better way to check for this...
Expand Down
4 changes: 3 additions & 1 deletion dcp/initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ def fn_wrapper(*args, **kwargs):
for arg in args:
if js.utils.throws_in_pm(arg):
raise Exception(f'{type(arg)} is not supported in PythonMonkey')
ret_val = aio.blockify(prop_ref)(*args, **kwargs)
# If function takes BF2 objects, the underlying JS proxy must be passed instead
unwrapped_args = tuple(arg.js_ref if hasattr(arg, 'js_ref') else arg for arg in args)
ret_val = aio.blockify(prop_ref)(*unwrapped_args, **kwargs)
return _wrap_js('dynamically_accessed_property', ret_val)
return fn_wrapper

Expand Down
97 changes: 97 additions & 0 deletions tests/test_js_wrappers/test_object_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import unittest
import pythonmonkey as pm
from dcp.initialization import _wrap_js

JSCookieJar = pm.eval("""
class CookieJar
{
constructor(...cookies)
{
this.cookies = []
for (var cookie of cookies) {
this.addCookie(cookie)
}
}
addCookie(cookie)
{
this.cookies.push(cookie)
}
topCookie()
{
return this.cookies.at(-1)
}
}
CookieJar;
""")

JSCookie = pm.eval("""
class Cookie
{
constructor(flavor)
{
this.flavor = flavor
}
}
Cookie;
""")

PyCookie = _wrap_js("Cookie", JSCookie)
PyCookieJar = _wrap_js("CookieJar", JSCookieJar)


class TestObjectUnwrapping(unittest.TestCase):

def test_primitive_args_func(self):
# ensure wrapped functions return correct primitives
bf_fn = _wrap_js('test_fn', pm.eval('(x) => x'))
self.assertEqual(bf_fn("Hello"), "Hello")
self.assertEqual(type(bf_fn(7)), float)

def test_bifrost_args_func(self):
# object must be unwrapped before being passed to pm
bf_fn = _wrap_js('test_fn', pm.eval('(cookie) => cookie instanceof Cookie'))
cookie = PyCookie('chocolate chip')
self.assertTrue(bf_fn(cookie))

# returned object must be wrapped
bf_fn = _wrap_js('test_fn', pm.eval('(cookie) => cookie'))
cookie = PyCookie('chocolate chip')
self.assertEqual(type(bf_fn(cookie)), PyCookie)

def test_primitive_args_ctor(self):

cookie = PyCookie('chocolate chip')

# Verify object is wrapped properly
self.assertEqual(type(cookie), PyCookie)
self.assertTrue(hasattr(cookie, 'js_ref'))
self.assertEqual(cookie.flavor, 'chocolate chip')

# Verify underlying object is the right class
self.assertTrue(pm.eval('(cookie) => cookie instanceof Cookie')(cookie.js_ref))

def test_bifrost_args_ctor(self):

cookie_one = PyCookie('chocolate chip')
cookie_two = PyCookie('oatmeal')

# Constructors that take bf2 objects must unwrap them
py_jar = PyCookieJar(cookie_one, cookie_two)

# Attributes and obj need to be the correct type when obtained in underlying js
js_fn = pm.eval('(jar) => jar instanceof CookieJar && jar.topCookie() instanceof Cookie')
self.assertTrue(js_fn(py_jar.js_ref))

def test_bifrost_args_method(self):

py_jar = PyCookieJar()

# bf2 objects passed as function arguments must be unwrapped
py_jar.addCookie( PyCookie('chocolate chip') )
js_fn = pm.eval('(jar) => jar.topCookie() instanceof Cookie')

self.assertTrue(js_fn(py_jar.js_ref))


if __name__ == '__main__':
unittest.main()
Loading