FloatPanel with Dtale Session and Status Change on Closure

FloatPanel does not initiate a status change when clicking the close icon. I think it is due to JsPanel not sending a status change for close. The following code extends FloatPanel to add onbeforeclose, to end the dtale session.

Thanks to @matthiasautrata.

import gc

import dtale
import pandas as pd
import panel as pn
from werkzeug.serving import BaseWSGIServer

pn.extension('floatpanel')


# Be careful using this if you have other Dtale Sessions open
def proper_dtale_shutdown():
    for obj in gc.get_objects():
        try:
            if isinstance(obj, BaseWSGIServer):
                obj.shutdown()
                break
        except Exception as e:
            print(e)
    dtale.global_state.cleanup()


class CustomFloatPanel(pn.layout.FloatPanel):
    def __init__(self, *objects, name='', **params):
        super().__init__(*objects, name=name, **params)
        self._scripts[
            'render'
        ] = """
            if (state.panel) {
              view.run_script('close')
            }
            var config = {
              headerTitle: data.name,
              content: float,
              theme: data.theme,
              id: 'jsPanel'+data.id,
              position: view.run_script('get_position'),
              contentSize: `${model.width} ${model.height}`,
              onstatuschange: function() {
                data.status = this.status
              },
              onbeforeclose: function(panel, status, closedByUser) {
                data.status = 'closed'
              }
            }
            if (data.contained) {
              config.container = view.container
            }
            config = {...config, ...data.config}
            state.panel = jsPanel.create(config);
        """
        self.param.watch(self.close_dtale_session, 'status')

    def close_dtale_session(self, event):
        if self.status == 'closed' and self.dt and dtale.get_instance(self.dt._data_id):
            # .kill() does not currently work on dtale version 3.3.0
            # utilizing their workaround
            proper_dtale_shutdown()
            self.objects = []


df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
dt = dtale.show(df, host='localhost')
html = f""" <iframe src="{dt._main_url}" width="1000" height="1000"></iframe> """

float_panel = CustomFloatPanel(html, name='Browse Database', margin=20)
float_panel.dt = dt

pn.serve(float_panel)

2 Likes