|
|
"""Base class to manage widgets"""
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
# Copyright (C) 2013 The IPython Development Team
|
|
|
#
|
|
|
# Distributed under the terms of the BSD License. The full license is in
|
|
|
# the file COPYING, distributed as part of this software.
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
# Imports
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
from weakref import ref
|
|
|
|
|
|
from IPython.config import LoggingConfigurable
|
|
|
from IPython.core.prompts import LazyEvaluate
|
|
|
from IPython.core.getipython import get_ipython
|
|
|
from IPython.utils.traitlets import Instance, Unicode, Dict, Any
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
# Code
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
def lazy_keys(dikt):
|
|
|
"""Return lazy-evaluated string representation of a dictionary's keys
|
|
|
|
|
|
Key list is only constructed if it will actually be used.
|
|
|
Used for debug-logging.
|
|
|
"""
|
|
|
return LazyEvaluate(lambda d: list(d.keys()))
|
|
|
|
|
|
class WidgetManager(LoggingConfigurable):
|
|
|
"""Manager for Widgets in the Kernel"""
|
|
|
|
|
|
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
|
|
|
def _shell_default(self):
|
|
|
return get_ipython()
|
|
|
iopub_socket = Any()
|
|
|
def _iopub_socket_default(self):
|
|
|
return self.shell.parent.iopub_socket
|
|
|
session = Instance('IPython.kernel.zmq.session.Session')
|
|
|
def _session_default(self):
|
|
|
if self.shell is None:
|
|
|
return
|
|
|
return self.shell.parent.session
|
|
|
|
|
|
widgets = Dict()
|
|
|
|
|
|
# Public APIs
|
|
|
|
|
|
def register_widget(self, widget):
|
|
|
"""Register a new widget"""
|
|
|
self.widgets[widget.widget_id] = ref(widget)
|
|
|
widget.shell = self.shell
|
|
|
widget.iopub_socket = self.iopub_socket
|
|
|
widget.create()
|
|
|
return widget.widget_id
|
|
|
|
|
|
def unregister_widget(self, widget_id):
|
|
|
"""Unregister a widget, and destroy its counterpart"""
|
|
|
# unlike get_widget, this should raise a KeyError
|
|
|
widget_ref = self.widgets.pop(widget_id)
|
|
|
widget = widget_ref()
|
|
|
if widget is None:
|
|
|
# already destroyed, nothing to do
|
|
|
return
|
|
|
widget.destroy()
|
|
|
|
|
|
def get_widget(self, widget_id):
|
|
|
"""Get a widget with a particular id
|
|
|
|
|
|
Returns the widget if found, otherwise None.
|
|
|
|
|
|
This will not raise an error,
|
|
|
it will log messages if the widget cannot be found.
|
|
|
"""
|
|
|
if widget_id not in self.widgets:
|
|
|
self.log.error("No such widget: %s", widget_id)
|
|
|
self.log.debug("Current widgets: %s", lazy_keys(self.widgets))
|
|
|
return
|
|
|
# call, because we store weakrefs
|
|
|
widget = self.widgets[widget_id]()
|
|
|
if widget is None:
|
|
|
self.log.error("Widget %s has been removed", widget_id)
|
|
|
del self.widgets[widget_id]
|
|
|
self.log.debug("Current widgets: %s", lazy_keys(self.widgets))
|
|
|
return
|
|
|
return widget
|
|
|
|
|
|
# Message handlers
|
|
|
|
|
|
def widget_update(self, stream, ident, msg):
|
|
|
"""Handler for widget_update messages"""
|
|
|
content = msg['content']
|
|
|
widget_id = content['widget_id']
|
|
|
widget = self.get_widget(widget_id)
|
|
|
if widget is None:
|
|
|
# no such widget
|
|
|
return
|
|
|
widget.handle_update(content['data'])
|
|
|
|
|
|
def widget_destroy(self, stream, ident, msg):
|
|
|
"""Handler for widget_destroy messages"""
|
|
|
content = msg['content']
|
|
|
widget_id = content['widget_id']
|
|
|
widget = self.get_widget(widget_id)
|
|
|
if widget is None:
|
|
|
# no such widget
|
|
|
return
|
|
|
widget.handle_destroy(content['data'])
|
|
|
del self.widgets[widget_id]
|
|
|
|
|
|
|
|
|
__all__ = ['WidgetManager']
|
|
|
|