jupyter-widgets / ipywidgets

Interactive Widgets for the Jupyter Notebook
https://ipywidgets.readthedocs.io
BSD 3-Clause "New" or "Revised" License
3.16k stars 950 forks source link

Asynchronous "show/hide" TexteArea works in the classic Notebook but doesn't in JupyterLab #2918

Open nleclercq opened 4 years ago

nleclercq commented 4 years ago

In our use case, the idea is to popup an TextArea when an error occurred in an asynchronous process and to hide it when the error condition disappears. The implementation uses a dedicated Output to display the TextArea when an error occurred. The Output.clear_output is then called to remove the TextArea when the problem is fixed.

In the following code, the asynchronous activity is simulated by a thread. This works smoothly in the classic Notebook but doesn't behave as expected in JupyterLab : the TextArea doesn't show up or remains displayed. The ipywidgets Jupyterlab extension is (obviously) properly installed and works as expected in other contexts.

Here is the Conda configuration I'm using:

ipykernel       5.3.1       py37h43977f1_0  conda-forge
ipython         7.16.1      py37h43977f1_0  conda-forge
ipython_genutil     0.2.0       py_1        conda-forge
ipywidgets      7.5.1       py_0        conda-forge
jupyter_client      6.1.5       py_0        conda-forge
jupyter_core        4.6.3       py37hc8dfbb8_1  conda-forge
jupyterlab      2.1.5       py_0        conda-forge
jupyterlab_server   1.2.0       py_0        conda-forge
notebook        6.0.3       py37hc8dfbb8_0  conda-forge 
python          3.7.7       hcff3b4d_5 
widgetsnbextension  3.5.1       py37_0      conda-forge
traitlets       4.3.3       py37hc8dfbb8_1  conda-forge

Here is some code reproducing the problem:

import threading
import time
from IPython.display import display
import ipywidgets as widgets

class AsyncErrorArea(object):

    def __init__(self):
        self.cnt = 0
        self.err = False
        self.wta = widgets.Textarea(layout = widgets.Layout(flex='1 1 auto', width='auto'),
                                    placeholder='You should not see this TextArea!',
                                    disabled=True) 
        weo_layout = widgets.Layout(flex='1 1 auto', width='auto')
        weo_layout.border = "1px solid grey"
        self.weo = widgets.Output(layout=weo_layout)
        display(self.weo)

    def show_error(self, err):
        try:
            self.err = True
            txt = "Oops, the following error occurred: " + err
            self.wta.value = txt
            self.wta.rows = 2
            with self.weo:
                display(self.wta)
            self.weo.layout.border = ""
        except Exception as e:
            print(e)

    def hide_error(self):
        try:
            self.err = False
            self.wta.value = ""
            self.weo.clear_output()
            self.weo.layout.border = "1px solid grey"
        except Exception as e:
            print(e)

    def simul_activity(self):
        try:
            while not self.exit_requested:
                self.cnt += 1
                if not self.cnt % 3:
                    self.show_error("error #{}".format(self.cnt))
                elif self.err:
                    self.hide_error()
                time.sleep(1.)
        except Exception as e:
            print(e)

    def start(self):
        self.exit_requested = False
        self.thread = threading.Thread(target=self.simul_activity)
        self.thread.start()

    def exit(self):
        self.exit_requested = True
        self.thread.join()
aea = AsyncErrorArea()
aea.start()
aea.exit()
nleclercq commented 2 years ago

Ping