Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widget support for SoS Notebook. #234

Closed
BoPeng opened this issue Jul 10, 2019 · 15 comments
Closed

Widget support for SoS Notebook. #234

BoPeng opened this issue Jul 10, 2019 · 15 comments

Comments

@BoPeng
Copy link
Contributor

BoPeng commented Jul 10, 2019

SoS kernel blocks communication between kernels and frontend so that progress bar and other widgets from subkernels stopped working. We ignored this problem before but should try to address it now.

The following is just an example from tqdm webpage:

from tqdm import tnrange, tqdm_notebook
from time import sleep

for i in tnrange(3, desc='1st loop'):
    for j in tqdm_notebook(range(100), desc='2nd loop'):
        sleep(0.01)

image

@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 10, 2019

Similar effect in

import ipywidgets as widgets
widgets.IntSlider()

image

@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 10, 2019

This is the illustration and we need to think how to insert the SoS kernel in it.

https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Low%20Level.html

image

@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 15, 2019

image

Output of widgets works, but interactions still not (frontend sending message to subkernel directly).

@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 15, 2019

Note that ipywidget saves parent_header's msg_id for internal use, and we will need to keep msg_id consistent.

https://github.com/jupyter-widgets/ipywidgets/blob/67af059687205f10a339472f72cd86d2b34948c2/ipywidgets/widgets/widget_output.py#L50-L55

@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 15, 2019

Try to organize my thought on what is happening:

  1. When SoS execute a cell, an execute_request is sent with a msg_id (let us name it sos_msg_id). This is the "master message" for the cell, and should be the parent_header of all messages if anything needs to be displayed in the notebook. Note that this msg_id appears to be created by the frontend, and used by the frontend to display only relevant messages.

  2. SoS calls run_cell and send the code to the subkernel with another execute_request message, which returns another msg_id (named subkernel_msg_id).

  3. SoS monitors output from the kernel. All messages have a parent_header of the subkernel_msg_id. SoS resend the messages with sos_msg_id so that they can be displayed in SoS notebook.

The problem with widgets is that the widgets are created with the subkernel_msg_id. Here are what will happen

  1. If we send comm_open messages with sos_msg_id, the widget will not work because the sos kernel does not handle widget.

  2. If we send comm_open messages with subkernel_msg_id, the widget will not be displayed because the header IDs are different.

It seems necessary to translate the IDs or force the use of sos_msg_id in subkernel_msg_id.

BoPeng pushed a commit that referenced this issue Jul 15, 2019
@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 16, 2019

OK, the frontend comm_msg works like this:

  1. When the subkernel sends comm_open message, the SoS kernel can record who is creating what comm.
  2. When the user presses a frontend widget, some comm_msg will be sent to the SoS kernel.
  3. The SoS kernel looks up the subkernel and forward the comm_msg to the subkernel.
  4. The subkernel sometimes sends some responses to ioPub
  5. The SoS kernel catches and forward it to the frontend.

The problem is with 4, because SoS does not actively listen to comm_msg messages from iopub subkernels (it only checks it when the subkernel is being executed). Therefore the SoS will not be able to process the comm_msg in time.

To solve this problem, the SoS kernel will have to actively check ioPub channel of all subkernels and forward comm_msg to the frontend.

BoPeng pushed a commit that referenced this issue Jul 16, 2019
@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 17, 2019

Finally, the solution is to add a function that forward all ioPub messages to frontend even when no cell is being evaluated. This allows frontend actions to be handled by the SoS kernel.

image

The function is called by the controller in the controller's messaging loop in a separate thread so it responds a bit slower than the native widgets.

@ktaletsk
Copy link

ktaletsk commented Jul 31, 2019

Hi @BoPeng , thank you for this fix! I can't make it fully working, though. I am able to create the widget in Python3 subkernel and interact with it, but the number below is not updated. It is working fine in the SoS kernel or in vanilla Python3 notebook. It is possible that I am not installing something properly, so I give the sequence of steps below:

  1. Use the latest jupyter-minimal container:
    docker run -it -p 8888:8888 jupyter/minimal-notebook:307ad2bb5fce /bin/bash

  2. Install ipywidgets, verify they work

    a. conda install -c conda-forge ipywidgets
    b. jupyter labextension install @jupyter-widgets/jupyterlab-manager
    c. Start Jupyter Lab
    d. Create a notebook with the following cell:

    from ipywidgets import interact, interactive, fixed, interact_manual
    import ipywidgets as widgets
    def f(x):
    		return x
    interact(f, x=10);
    
  3. Install SoS and try interactive widgets again
    a. pip install sos==0.19.14 sos-notebook==0.19.14 sos-python==0.18.1
    b. python -m sos_notebook.install
    c. jupyter labextension install jupyterlab-sos
    d. Start Jupyter, choose SoS kernel, choose Python3 subkernel
    e. Run the same cell
    f. The number below is not updated and stays at 10

Screen Shot 2019-07-31 at 1 42 49 PM

@BoPeng BoPeng reopened this Jul 31, 2019
@ktaletsk
Copy link

Update: the same problem if installing from the latest GitHub version (which I should have used):

pip install git+https://github.com/vatlab/sos
pip install git+https://github.com/vatlab/sos-notebook.git
pip install git+https://github.com/vatlab/sos-python.git

@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 31, 2019

I only tested for classic jupyter and I am testing JupyterLab now. It is likely that jupyterlab-sos is not playing well with @jupyter-widgets.

@ktaletsk
Copy link

@BoPeng you are right indeed. If I do not install @jupyter-widgets, widgets are fully working in the classic notebook, but obviously not in the JupyterLab. If I install @jupyter-widgets, it does not work anywhere, not classic, not JupyterLab

@BoPeng
Copy link
Contributor Author

BoPeng commented Jul 31, 2019

Here with @jupyterlab-widgets installed widgets in classic jupyter works... As far as I can tell the sos kernel is sending the correct messages to the frontend and I am trying to figure out why the linked number is not updated.

@BoPeng
Copy link
Contributor Author

BoPeng commented Aug 2, 2019

After hours of message tracing, I finally understand what is going on here but I am not sure if I can find a solution. Allow me to explain the problem in detail:

image

  1. When the slider is clicked, a comm_msg is generated, and is forwarded to the subkernel by SoS.
  2. The subkernel respond with a series of messages, status (busy), comm_msg, clear_output, display_data, comm_msg, and status (idle). These messages are forwarded by SoS to the frontend, and updates the widget.

This is how widget is supported by SoS Notebook.

In JupyterLab, the same messages are sent but the frontend is not updated. Under the hood the following has happened:

  1. When the slide is clicked, a comm_msg is generated, and is forwarded to the subkernel by SoS.
  2. The SoS kernel sent messages status (busy) and status (idle) to the frontend. Because the future set for comm_msg is resolved by the appearance of status (idle), the comm_msg future is resolved and removed from this._futures.
  3. When a series of messages are forwarded from subkernel to frontend, they are ignored because the parent message comm_msg has already been resolved.

So the difference between classic Jupyter and JupyterLab is the status response of the SoS kernel to the comm_msg. The only "proper" solution seems to put the SoS kernel in busy mode with comm_msg.

BoPeng pushed a commit that referenced this issue Aug 2, 2019
@BoPeng
Copy link
Contributor Author

BoPeng commented Aug 2, 2019

@ktaletsk I have submitted a patch. Please let me know if widget support is still not working on your side.

@ktaletsk
Copy link

ktaletsk commented Aug 2, 2019

@BoPeng it is working, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants