AaronWatters / jp_proxy_widget

Generic Jupyter/IPython widget implementation that will support many types of javascript libraries and interactions.
BSD 2-Clause "Simplified" License
61 stars 13 forks source link

Nested object properties bind to 'None' #14

Closed camilledupont closed 3 years ago

camilledupont commented 3 years ago

Using Python 3 in Jupyter Notebook, and jp_proxy_widget v1.0.8.

Multi-level object send in javascript callback to python results in None for nested properties:

import jp_proxy_widget
from IPython.display import display

def printing_callback(*args):
    print(args)

# Python code here to create the widget

widget = jp_proxy_widget.JSProxyWidget()
widget.js_init("""

element.html("<button main>Click</button>");
const div = document.querySelector("[main]");
div.addEventListener('click', () => {
callback([{prop1: "test", prop2: {subprop2: "toto"}}])
})
""",callback=printing_callback)

# display the widget
display(widget.debugging_display())

result

Did I miss something ?

AaronWatters commented 3 years ago

Yes, there is a recursion limit on translating objects from Javascript to Python:

Proxy widgets allow Javascript to send JSON compatible data to Python up to a specified recursion limit. https://github.com/AaronWatters/jp_proxy_widget/blob/master/notebooks/Tutorial_as_markdown.md

In js_init please try callable_level=5 or something like that.

The reason for the limit is that if you try to transfer an object that is too big (or self referencing) you can crash the browser and there is no way to break the underlying Javascript out of an infinite loop.

update: Just tested this and it worked:


import jp_proxy_widget
from IPython.display import display

def printing_callback(*args):
    print(args)

# Python code here to create the widget

widget = jp_proxy_widget.JSProxyWidget()
widget.js_init("""

element.html("<button main>Click</button>");
const div = document.querySelector("[main]");
div.addEventListener('click', () => {
callback([{prop1: "test", prop2: {subprop2: "toto"}}])
})
""",callback=printing_callback, callable_level=5)

# display the widget
display(widget.debugging_display())