I have a website that performs file format conversions, and this service can be used by other websites via the window.postMessage system. It would be great if one could do this also via a Jupyter notebook. I run however into a serious issue. I can get python to create a Javascript command that sends a file in format A to the website, and I can access the response (file in format B) in Javascript after some delay, but I cannot get the response from Javascript back into Python for further processing. I have made an as-simple-as-possible notebook to demonstrate the issue. The reason seems to be that Python first executes all cells (in the Run all scenario) and only then looks at any new execution requests.
There are similar questions on stackoverflow, for example here: IPython Notebook Javascript: retrieve content from JavaScript variables. From what I found so far there is no solution to the problem. I find that very disappointing, because it would be so cool to create webservices that are directly accessible from Jupyter notebooks, without having to go the node.js route.
import asyncio, time
from IPython.display import display, Javascript
The code below inserts Javascript into the page: The 'sendRequest' function is just a five second delay, but it is intended to communicate with another webpage via window.postMessage.
futureResponse is an asyncio Future (python). It gets a result when sendRequest (Javascript) finishes and uses kernel.execute (Javascript) to call the responseHandler (python).
global futureResponse
def responseHandler(response):
futureResponse.set_result(response)
display(Javascript("""
window.responseHandler = (response) => {
var kernel = IPython.notebook.kernel;
var pyCommand = 'responseHandler(\\''+response+'\\')';
kernel.execute(pyCommand);
console.log('responseHandler called')
};
window.sendRequest = () => {
return new Promise( (resolve,reject) => { setTimeout(()=>resolve('RESPONSE'),5000) } )
}
"""))
The code below inserts Javascript that calls sendRequest. That will call responseHandler (Javascript) after the setTimeout delay (5 s), which calls kernel.execute which invokes responseHandler (python), which sets the result of futureResponse. However, if I use "await futureResponse", it never fulfills.
# the value of futureResponse will be set by the responseHandler
futureResponse = asyncio.Future()
display(Javascript("""
window.sendRequest().then(
(response) => window.responseHandler(response)
)
"""))
# This does not work (futureResponse unresolved):
time.sleep(6)
# With await, the notebook keeps waiting forever.
#await futureResponse
print(futureResponse)
If the cell below is evaluated immediately after the previous cell (as in a Run all scenario), then futureResponse is still unresolved. But if it is evaluated 5 seconds later, futureResponse has the value "RESPONSE".
futureResponse