Search code examples
pythonvuetify.jsjupyterjupyter-labipywidgets

why cannot I print in jupyter lab using ipywidgets class?


I use the ipyvuetify librairy to create dashboard in a Jupyter environment. The lib works super nicely but I'm struggling with Jupyterlab and voila that seems to have the same behavior with respect to this problem:

let's assume I want to create a widget that when clicked print a message :

import ipyvuetify as v 

class Test(v.Btn):
    
    def __init__(self, msg):
        
        self.msg = msg
        
        super().__init__(children=['click'])
        
        self.on_event('click', self._on_click)
        
    def _on_click(self, widget, event, data):
        
        print(self.msg)
        
        return
    
btn = Test(toto)
btn

If I run this code from Jupyter Notebook, everything works fine, the msg is printed after the btn cell output. If I do the same in Jupyterlab, the print statement ends up in the log.

now if run :

btn._on_click(None, None, None)

the msg is printed in both Jupyterlab and Jupyter Notebook.

Can someone explain me why there is a behaviour difference and maybe how to make sure that my print statement ends up in the main workflow and not in the log ?


Solution

  • Indeed, JupyterLab has implemented a different mechanism than Jupyter Notebook to capture output, via the Output widget of ipywidget:

    import ipyvuetify as v
    import ipywidgets as w
    
    class Test(v.Btn):
        output = w.Output()
        def __init__(self, msg):
            
            self.msg = msg
            
            super().__init__(children=['click'])
            
            self.on_event('click', self._on_click)
            
        @output.capture()
        def _on_click(self, widget, event, data):
            
            print(self.msg)
            
            return
    
        def _ipython_display_(self):
            display(super(),self.output)
    
        
    btn = Test('toto')
    btn
    

    Ipywidget documentation: the output from _on_click is directed to output by using either a context manager with self.output: over print(), or the capture decorator to capture all the output produced by the _on_click function (example above).

    Some explanation in https://github.com/jupyterlab/jupyterlab/issues/3151#issuecomment-339476572:

    We kludged a backwards-compatibility workaround in the classic notebook, but we didn't in jupyterlab. Part of the reason is that it is much harder to write kludgy workarounds in jlab :).

    Essentially, the technical issue is that a widget comm message from the browser to the client would need to set the output callback to append output to the current output area - but IIRC it's hard from a mime renderer to get a handle on the output area that contains it.