back to Index

widgets_spinonce

  • IPython Notebook widgets.spinOnce()

IPython Widgets spinOnce

Searching for documentation...

ipython github wiki

https://github.com/ipython/ipython/wiki

not that useful.

ipython.org/ipython-doc

http://ipython.org/ipython-doc/2/index.html ->

http://ipython.org/ipython-doc/2/development/index.html ->

http://ipython.org/ipython-doc/2/development/messaging.html -->

http://ipython.org/ipython-doc/2/development/messaging.html#comm-messages

Comm messages are one-way communications to update comm state, used for synchronizing widget state, or simply requesting actions of a comm’s counterpart.

Searching for widget callback


In [2]:
ls


2014-07-12.ipynb  index.ipynb

In [5]:
cp /projects/0a592ce8-7730-49b4-baed-e8ce6f939851/ipython/ . -r

In [9]:
!grep -r 'comm_msg' .


./.ipynb_checkpoints/2014-07-12-checkpoint.ipynb:        "./ipython/IPython/html/static/services/kernels/js/comm.js:        var msg_types = ['comm_open', 'comm_msg', 'comm_close'];\r\n",
./.ipynb_checkpoints/2014-07-12-checkpoint.ipynb:        "./ipython/IPython/kernel/zmq/ipkernel.py:        comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]\r\n"
./ipython/IPython/html/static/services/kernels/js/comm.js:        var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
./ipython/IPython/html/static/services/kernels/js/comm.js:    CommManager.prototype.comm_msg = function (msg) {
./ipython/IPython/html/static/services/kernels/js/comm.js:        return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata);
./ipython/IPython/html/static/widgets/js/widget.js:                comm.on_msg($.proxy(this._handle_comm_msg, this));
./ipython/IPython/html/static/widgets/js/widget.js:        _handle_comm_msg: function (msg) {
./ipython/IPython/kernel/comm/comm.py:        self._publish_msg('comm_msg', data, metadata)
./ipython/IPython/kernel/comm/comm.py:        """Register a callback for comm_msg
./ipython/IPython/kernel/comm/comm.py:        Will be called with the `data` of any comm_msg messages.
./ipython/IPython/kernel/comm/comm.py:        """Handle a comm_msg message"""
./ipython/IPython/kernel/comm/manager.py:    def comm_msg(self, stream, ident, msg):
./ipython/IPython/kernel/comm/manager.py:        """Handler for comm_msg messages"""
./ipython/IPython/kernel/comm/manager.py:            self.log.error("Exception in comm_msg for %s", comm_id, exc_info=True)
./ipython/IPython/kernel/zmq/ipkernel.py:        comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
./ipython/IPython/kernel/zmq/ipkernel.py:        for msg_type in comm_msg_types:
gets/js/manager.js:        WidgetManager.prototype._handle_comm_open = function (comm, msg) {\r\n./ipython/IPython/kernel/comm/comm.py:    _open_data = Dict(help=\"data dict, if any, to be included in comm_open\")\r\n./ipython/IPython/kernel/comm/comm.py:        self._publish_msg('comm_open', data, metadata, target_name=self.target_name)\r\n./ipython/IPython/kernel/comm/manager.py:        f will be called with two arguments when a comm_open message is received with `target`:\r\n./ipython/IPython/kernel/comm/manager.py:        - the `comm_open` message itself.\r\n./ipython/IPython/kernel/comm/manager.py:    def comm_open(self, stream, ident, msg):\r\n./ipython/IPython/kernel/comm/manager.py:        \"\"\"Handler for comm_open messages\"\"\"\r\n./ipython/IPython/kernel/zmq/ipkernel.py:        comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]\r\n","stream":"stdout"}],"language":"python","trusted":true,"collapsed":false}
./.2014-07-12.ipynb.syncdoc:{"metadata":{},"cell_type":"code","input":"!grep -r 'comm_open' .","prompt_number":8,"outputs":[{"output_type":"stream","text":"./ipython/IPython/html/static/services/kernels/js/comm.js:        var msg_types = ['comm_open', 'comm_msg', 'comm_close'];\r\n./ipython/IPython/html/static/services/kernels/js/comm.js:    CommManager.prototype.comm_open = function (msg) {\r\n./ipython/IPython/html/static/services/kernels/js/comm.js:        return this.kernel.send_shell_message(\"comm_open\", content, callbacks, metadata);\r\n./ipython/IPython/html/static/widgets/js/manager.js:                that.comm_manager.register_target(model_name, $.proxy(that._handle_comm_open, that));\r\n./ipython/IPython/html/static/widgets/js/manager.js:                    instance.comm_manager.register_target(model_name, $.proxy(instance._handle_comm_open, instance));\r\n./ipython/IPython/html/static/widgets/js/manager.js:        WidgetManager.prototype._handle_comm_open = function (comm, msg) {\r\n./ipython/IPython/kernel/comm/comm.py:    _open_data = Dict(help=\"data dict, if any, to be included in comm_open\")\r\n./ipython/IPython/kernel/comm/comm.py:        self._publish_msg('comm_open', data, metadata, target_name=self.target_name)\r\n./ipython/IPython/kernel/comm/manager.py:        f will be called with two arguments when a comm_open message is received with `target`:\r\n./ipython/IPython/kernel/comm/manager.py:        - the `comm_open` message itself.\r\n./ipython/IPython/kernel/comm/manager.py:    def comm_open(self, stream, ident, msg):\r\n./ipython/IPython/kernel/comm/manager.py:        \"\"\"Handler for comm_open messages\"\"\"\r\n./ipython/IPython/kernel/zmq/ipkernel.py:        comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]\r\n","stream":"stdout"}],"language":"python","trusted":true,"collapsed":false}

In [13]:
!grep -r 'monitor.send(' .


./..2014-07-12.ipynb.syncdoc.sage-backup:{"metadata":{},"cell_type":"code","input":"!grep -r 'monitor.send(' .","prompt_number":11,"outputs":[],"language":"python","trusted":true,"collapsed":false}

Usage

https://github.com/cournape/traitlets

Conclusions: how to use traitlets.


In [18]:
import IPython.utils.traitlets
from IPython.utils.traitlets import link, CFloat, Float, HasTraits, Unicode, Long

In [19]:
class Employee(HasTraits):
    name = Unicode()
    age = Long()

In [27]:
dilbert = Employee(name="dilbert", age=35)

In [28]:
dilbert.age


Out[28]:
35L

In [29]:
doug = Employee(name="doug", age=21)

In [30]:
link((dilbert, 'age'), (doug, 'age'))


Out[30]:
<IPython.utils.traitlets.link at 0x262ac10>

In [31]:
doug.age


Out[31]:
35L

In [32]:
dilbert.age=22

In [33]:
doug.age


Out[33]:
22L

In [34]:
doug.age=60

In [35]:
dilbert.age


Out[35]:
60L

Next: see how the widgets interface with javascript

Looking at previous custom widget implementation

battlecruiser_widget.ipynb


In [38]:
from IPython.html import widgets # Widget definitions
from IPython.display import display # Used to display widgets in the notebook
from IPython.utils.traitlets import Unicode # Used to declare attributes of our widget
from IPython.display import HTML, Javascript
from IPython.html.widgets.widget_bool import _BoolWidget
from IPython.html.widgets.widget_float import _FloatWidget
from IPython.utils.traitlets import CInt, CFloat, Unicode
from IPython.html.widgets.widget import DOMWidget

class BattleCruiserView(DOMWidget):
    _view_name = Unicode('BattleCruiserView', sync=True)
    value = CFloat(0.0, help="Float value", sync=True)
    axis_id = CInt(0, help='axis_id', sync=True)
    x = CFloat(0.0, help="Position (x) of the battlecruiser", sync=True)
    y = CFloat(0.0, help="Position (y) of the battlecruiser", sync=True)
    theta = CFloat(0.0, help="Orientation (degrees) of the battlecruiser", sync=True)
    mouse_x = CFloat(0.0, help="Position (x) of the cursor", sync=True)
    mouse_y = CFloat(0.0, help="Position (y) of the cursor", sync=True)
    description = Unicode('', help="Description of the float (label).", sync=True)

DomWidget extends Widget extends LoggingConfigurable extends Configurable extends HasTraits

class DOMWidget(Widget):

The Widget class appears to contain the callbacks!


In [41]:
!grep -r 'class LoggingConfigurable' .


./ipython/IPython/config/configurable.py:class LoggingConfigurable(Configurable):

Testing...


In [43]:
slider=widgets.FloatSliderWidget()

In [44]:
slider

In [46]:
slider.value


Out[46]:
100.0

In [48]:
import time
for i in range (5):
    print(slider.value)
    time.sleep(1)


100.0
100.0
100.0
100.0
100.0

Slider doesn't update.

Widget: receiving state

class Widget(LoggingConfigurable):
    def _handle_receive_state(self, sync_data):
        """Called when a state is received from the front-end."""
        for name in self.keys:
            if name in sync_data:
                value = self._unpack_widgets(sync_data[name])
                with self._lock_property(name, value):
                    setattr(self, name, value)

Widget: general callback

class Widget(LoggingConfigurable):
    # Event handlers
    @_show_traceback
    def _handle_msg(self, msg):
        """Called when a msg is received from the front-end"""
        data = msg['content']['data']
        method = data['method']
        if not method in ['backbone', 'custom']:
            self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)

        # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
        if method == 'backbone' and 'sync_data' in data:
            sync_data = data['sync_data']
            self._handle_receive_state(sync_data) # handles all methods

        # Handle a custom msg from the front-end
        elif method == 'custom':
            if 'content' in data:
                self._handle_custom_msg(data['content'])

Widget: Registering callbacks

class Widget(LoggingConfigurable):
    @property
    def comm(self):
        """Gets the Comm associated with this widget.

        If a Comm doesn't exist yet, a Comm will be created automagically."""
        if self._comm is None:
            # Create a comm.
            self._comm = Comm(target_name=self._model_name)
            self._comm.on_msg(self._handle_msg)
            self._comm.on_close(self._close)
            Widget.widgets[self.model_id] = self

            # first update
            self.send_state()
        return self._comm

IPython/kernel/comm/comm.py!

Comm extends LoggingConfigurable extends Configurable extends HasTraits

Comm: handling comm message

class Comm(LoggingConfigurable):
    def handle_msg(self, msg):
        """Handle a comm_msg message"""
        self.log.debug("handle_msg[%s](%s)", self.comm_id, msg)
        if self._msg_callback:
            self.shell.events.trigger('pre_execute')
            self._msg_callback(msg)
            self.shell.events.trigger('post_execute')

Comm: sending messages

class Comm(LoggingConfigurable):
    def _publish_msg(self, msg_type, data=None, metadata=None, **keys):
        """Helper for sending a comm message on IOPub"""
        data = {} if data is None else data
        metadata = {} if metadata is None else metadata
        content = json_clean(dict(data=data, comm_id=self.comm_id, **keys))
        self.session.send(self.iopub_socket, msg_type,
            content,
            metadata=json_clean(metadata),
            parent=self.shell.get_parent(),
            ident=self.topic,
        )
    def send(self, data=None, metadata=None):
        """Send a message to the frontend-side version of this comm"""
        self._publish_msg('comm_msg', data, metadata)

Who registers this callback? Who calls this?


In [50]:
!grep -r 'handle_msg' .


./.ipynb_checkpoints/2014-07-12-checkpoint.ipynb:      "    def _handle_msg(self, msg):\n",
./.ipynb_checkpoints/2014-07-12-checkpoint.ipynb:      "            self._comm.on_msg(self._handle_msg)\n",
./.ipynb_checkpoints/2014-07-12-checkpoint.ipynb:      "    def handle_msg(self, msg):\n",
./.ipynb_checkpoints/2014-07-12-checkpoint.ipynb:      "        self.log.debug(\"handle_msg[%s](%s)\", self.comm_id, msg)\n",
./ipython/IPython/html/static/services/kernels/js/comm.js:            comm.handle_msg(msg);
./ipython/IPython/html/static/services/kernels/js/comm.js:    Comm.prototype.handle_msg = function (msg) {
./ipython/IPython/html/widgets/widget.py:            self._comm.on_msg(self._handle_msg)
./ipython/IPython/html/widgets/widget.py:    def _handle_msg(self, msg):
./ipython/IPython/kernel/comm/comm.py:    def handle_msg(self, msg):
./ipython/IPython/kernel/comm/comm.py:        self.log.debug("handle_msg[%s](%s)", self.comm_id, msg)
./ipython/IPython/kernel/comm/manager.py:            comm.handle_msg(msg)
       data = msg['content']['data']\n        method = data['method']\n        if not method in ['backbone', 'custom']:\n            self.log.error('Unknown front-end to back-end widget msg with method \"%s\"' % method)\n\n        # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.\n        if method == 'backbone' and 'sync_data' in data:\n            sync_data = data['sync_data']\n            self._handle_receive_state(sync_data) # handles all methods\n\n        # Handle a custom msg from the front-end\n        elif method == 'custom':\n            if 'content' in data:\n                self._handle_custom_msg(data['content'])\n```"}
./..2014-07-12.ipynb.syncdoc.sage-backup:{"metadata":{},"cell_type":"markdown","source":"Widget: Registering callbacks\n```python\nclass Widget(LoggingConfigurable):\n    @property\n    def comm(self):\n        \"\"\"Gets the Comm associated with this widget.\n\n        If a Comm doesn't exist yet, a Comm will be created automagically.\"\"\"\n        if self._comm is None:\n            # Create a comm.\n            self._comm = Comm(target_name=self._model_name)\n            self._comm.on_msg(self._handle_msg)\n            self._comm.on_close(self._close)\n            Widget.widgets[self.model_id] = self\n\n            # first update\n            self.send_state()\n        return self._comm\n```"}
./..2014-07-12.ipynb.syncdoc.sage-backup:{"metadata":{},"cell_type":"markdown","source":"Comm: handling comm message\n```python\nclass Comm(LoggingConfigurable):\n    def handle_msg(self, msg):\n        \"\"\"Handle a comm_msg message\"\"\"\n        self.log.debug(\"handle_msg[%s](%s)\", self.comm_id, msg)\n        if self._msg_callback:\n            self.shell.events.trigger('pre_execute')\n            self._msg_callback(msg)\n            self.shell.events.trigger('post_execute')\n            \n```\n"}
./.2014-07-12.ipynb.syncdoc:{"metadata":{},"cell_type":"markdown","source":"Widget: general callback\n\n```python\nclass Widget(LoggingConfigurable):\n    # Event handlers\n    @_show_traceback\n    def _handle_msg(self, msg):\n        \"\"\"Called when a msg is received from the front-end\"\"\"\n        data = msg['content']['data']\n        method = data['method']\n        if not method in ['backbone', 'custom']:\n            self.log.error('Unknown front-end to back-end widget msg with method \"%s\"' % method)\n\n        # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.\n        if method == 'backbone' and 'sync_data' in data:\n            sync_data = data['sync_data']\n            self._handle_receive_state(sync_data) # handles all methods\n\n        # Handle a custom msg from the front-end\n        elif method == 'custom':\n            if 'content' in data:\n                self._handle_custom_msg(data['content'])\n```"}
./.2014-07-12.ipynb.syncdoc:{"metadata":{},"cell_type":"markdown","source":"Widget: Registering callbacks\n```python\nclass Widget(LoggingConfigurable):\n    @property\n    def comm(self):\n        \"\"\"Gets the Comm associated with this widget.\n\n        If a Comm doesn't exist yet, a Comm will be created automagically.\"\"\"\n        if self._comm is None:\n            # Create a comm.\n            self._comm = Comm(target_name=self._model_name)\n            self._comm.on_msg(self._handle_msg)\n            self._comm.on_close(self._close)\n            Widget.widgets[self.model_id] = self\n\n            # first update\n            self.send_state()\n        return self._comm\n```"}
./.2014-07-12.ipynb.syncdoc:{"metadata":{},"cell_type":"markdown","source":"Comm: handling comm message\n```python\nclass Comm(LoggingConfigurable):\n    def handle_msg(self, msg):\n        \"\"\"Handle a comm_msg message\"\"\"\n        self.log.debug(\"handle_msg[%s](%s)\", self.comm_id, msg)\n        if self._msg_callback:\n            self.shell.events.trigger('pre_execute')\n            self._msg_callback(msg)\n            self.shell.events.trigger('post_execute')\n            \n```\n"}

What are: the

  • shell
  • io_pub
  • session

initialized:

class Comm(LoggingConfigurable):
    shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
    def _shell_default(self):
        return get_ipython()

    iopub_socket = Any()
    def _iopub_socket_default(self):
        return self.shell.kernel.iopub_socket
    session = Instance('IPython.kernel.zmq.session.Session')
    def _session_default(self):
        if self.shell is None:
            return
        return self.shell.kernel.session

What are:

  • Any
  • Instance
  • get_ipython
  • these classes

InteractiveShellABC:

class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
    """An abstract base class for InteractiveShell."""

InteractiveShellABC.register(InteractiveShell)
class InteractiveShell(SingletonConfigurable):
    """An enhanced, interactive shell for Python."""

IPython.kernel.zmq.session.Session:

class Session(Configurable):
    """Object for handling serialization and sending of messages.

    The Session object handles building messages and sending them
    with ZMQ sockets or ZMQStream objects.  Objects can communicate with each
    other over the network via Session objects, and only need to work with the
    dict-based IPython message spec. The Session will handle
    serialization/deserialization, security, and metadata.

    Sessions support configurable serialiization via packer/unpacker traits,
    and signing with HMAC digests via the key/keyfile traits.
    """

Comm hasa IPython.core.interactiveshell.InteractiveShellABC


In [ ]: