##// END OF EJS Templates
rename widget to comm
MinRK -
Show More
@@ -0,0 +1,152
1 """Base class for a Comm"""
2
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 import uuid
15
16 from IPython.config import LoggingConfigurable
17 from IPython.core.getipython import get_ipython
18
19 from IPython.utils.traitlets import Instance, Unicode, Bytes, Bool, Dict, Any
20
21 #-----------------------------------------------------------------------------
22 # Code
23 #-----------------------------------------------------------------------------
24
25 class Comm(LoggingConfigurable):
26
27 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
28 def _shell_default(self):
29 return get_ipython()
30 iopub_socket = Any()
31 def _iopub_socket_default(self):
32 return self.shell.parent.iopub_socket
33 session = Instance('IPython.kernel.zmq.session.Session')
34 def _session_default(self):
35 if self.shell is None:
36 return
37 return self.shell.parent.session
38
39 target = Unicode('comm')
40
41 topic = Bytes()
42 def _topic_default(self):
43 return ('comm-%s' % self.comm_id).encode('ascii')
44
45 _open_data = Dict(help="data dict, if any, to be included in comm_close")
46 _close_data = Dict(help="data dict, if any, to be included in comm_close")
47
48 _open_callback = Any()
49 _msg_callback = Any()
50 _close_callback = Any()
51
52 _closed = Bool(False)
53 comm_id = Unicode()
54 def _comm_id_default(self):
55 return uuid.uuid4().hex
56
57 primary = Bool(True, help="Am I the primary or secondary Comm?")
58
59 def __init__(self, **kwargs):
60 super(Comm, self).__init__(**kwargs)
61 get_ipython().comm_manager.register_comm(self)
62 if self.primary:
63 # I am primary, open my peer
64 self.open()
65 else:
66 # I am secondary, handle creation
67 self.handle_open(self._open_data)
68
69 def _publish_msg(self, msg_type, data=None, **keys):
70 """Helper for sending a comm message on IOPub"""
71 data = {} if data is None else data
72 self.session.send(self.iopub_socket, msg_type,
73 dict(data=data, comm_id=self.comm_id, **keys),
74 ident=self.topic,
75 )
76
77 def __del__(self):
78 """trigger close on gc"""
79 self.close()
80
81 # publishing messages
82
83 def open(self, data=None):
84 """Open the frontend-side version of this comm"""
85 if data is None:
86 data = self._open_data
87 self._publish_msg('comm_open', data, target=self.target)
88
89 def close(self, data=None):
90 """Close the frontend-side version of this comm"""
91 if self._closed:
92 # only close once
93 return
94 if data is None:
95 data = self._close_data
96 self._publish_msg('comm_close', data)
97 self._closed = True
98
99 def send(self, data=None):
100 """Update the frontend-side version of this comm"""
101 self._publish_msg('comm_msg', data)
102
103 # registering callbacks
104 def on_open(self, callback):
105 """Register a callback for comm_open
106
107 Will be called with the `data` of the open message.
108
109 Call `on_open(None)` to disable an existing callback.
110 """
111 self._open_callback = callback
112
113 def on_close(self, callback):
114 """Register a callback for comm_close
115
116 Will be called with the `data` of the close message.
117
118 Call `on_close(None)` to disable an existing callback.
119 """
120 self._close_callback = callback
121
122 def on_msg(self, callback):
123 """Register a callback for comm_msg
124
125 Will be called with the `data` of any comm_msg messages.
126
127 Call `on_msg(None)` to disable an existing callback.
128 """
129 self._msg_callback = callback
130
131 # handling of incoming messages
132
133 def handle_open(self, data):
134 """Handle a comm_open message"""
135 self.log.debug("handle_open[%s](%s)", self.comm_id, data)
136 if self._open_callback:
137 self._open_callback(data)
138
139 def handle_close(self, data):
140 """Handle a comm_close message"""
141 self.log.debug("handle_close[%s](%s)", self.comm_id, data)
142 if self._close_callback:
143 self._close_callback(data)
144
145 def handle_msg(self, data):
146 """Handle a comm_msg message"""
147 self.log.debug("handle_msg[%s](%s)", self.comm_id, data)
148 if self._msg_callback:
149 self._msg_callback(data)
150
151
152 __all__ = ['Comm']
@@ -0,0 +1,142
1 """Base class to manage comms"""
2
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 from IPython.config import LoggingConfigurable
15 from IPython.core.prompts import LazyEvaluate
16 from IPython.core.getipython import get_ipython
17
18 from IPython.utils.importstring import import_item
19 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
20
21 from .comm import Comm
22
23 #-----------------------------------------------------------------------------
24 # Code
25 #-----------------------------------------------------------------------------
26
27 def lazy_keys(dikt):
28 """Return lazy-evaluated string representation of a dictionary's keys
29
30 Key list is only constructed if it will actually be used.
31 Used for debug-logging.
32 """
33 return LazyEvaluate(lambda d: list(d.keys()))
34
35
36 class CommManager(LoggingConfigurable):
37 """Manager for Comms in the Kernel"""
38
39 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
40 def _shell_default(self):
41 return get_ipython()
42 iopub_socket = Any()
43 def _iopub_socket_default(self):
44 return self.shell.parent.iopub_socket
45 session = Instance('IPython.kernel.zmq.session.Session')
46 def _session_default(self):
47 if self.shell is None:
48 return
49 return self.shell.parent.session
50
51 comms = Dict()
52 targets = Dict()
53
54 # Public APIs
55
56 def register_target(self, target, f):
57 """Register a callable f for a given target
58
59 f will be called with a Comm object as its only argument
60 when a comm_open message is received with `target`.
61
62 f can be a Python callable or an import string for one.
63 """
64 if isinstance(f, basestring):
65 f = import_item(f)
66
67 self.targets[target] = f
68
69 def register_comm(self, comm):
70 """Register a new comm"""
71 comm_id = comm.comm_id
72 comm.shell = self.shell
73 comm.iopub_socket = self.iopub_socket
74 self.comms[comm_id] = comm
75 return comm_id
76
77 def unregister_comm(self, comm_id):
78 """Unregister a comm, and close its counterpart"""
79 # unlike get_comm, this should raise a KeyError
80 comm = self.comms.pop(comm_id)
81 comm.close()
82
83 def get_comm(self, comm_id):
84 """Get a comm with a particular id
85
86 Returns the comm if found, otherwise None.
87
88 This will not raise an error,
89 it will log messages if the comm cannot be found.
90 """
91 if comm_id not in self.comms:
92 self.log.error("No such comm: %s", comm_id)
93 self.log.debug("Current comms: %s", lazy_keys(self.comms))
94 return
95 # call, because we store weakrefs
96 comm = self.comms[comm_id]
97 return comm
98
99 # Message handlers
100
101 def comm_open(self, stream, ident, msg):
102 """Handler for comm_open messages"""
103 content = msg['content']
104 comm_id = content['comm_id']
105 target = content['target']
106 callback = self.targets.get(target, None)
107 comm = Comm(comm_id=comm_id,
108 shell=self.shell,
109 iopub_socket=self.iopub_socket,
110 _open_data=content['data'],
111 primary=False,
112 )
113 if callback is None:
114 self.log.error("No such comm target registered: %s", target)
115 comm.destroy()
116 return
117 callback(comm)
118 self.register_comm(comm)
119
120 def comm_msg(self, stream, ident, msg):
121 """Handler for comm_msg messages"""
122 content = msg['content']
123 comm_id = content['comm_id']
124 comm = self.get_comm(comm_id)
125 if comm is None:
126 # no such comm
127 return
128 comm.handle_msg(content['data'])
129
130 def comm_close(self, stream, ident, msg):
131 """Handler for comm_close messages"""
132 content = msg['content']
133 comm_id = content['comm_id']
134 comm = self.get_comm(comm_id)
135 if comm is None:
136 # no such comm
137 return
138 comm.handle_close(content['data'])
139 del self.comms[comm_id]
140
141
142 __all__ = ['CommManager']
@@ -6,141 +6,143
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Widget and WidgetManager bases
9 // Comm and CommManager bases
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * Base Widget classes
12 * Base Comm classes
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule widget
15 * @submodule comm
16 */
16 */
17
17
18 var IPython = (function (IPython) {
18 var IPython = (function (IPython) {
19 "use strict";
19 "use strict";
20
20
21 //-----------------------------------------------------------------------
21 //-----------------------------------------------------------------------
22 // WidgetManager class
22 // CommManager class
23 //-----------------------------------------------------------------------
23 //-----------------------------------------------------------------------
24
24
25 var WidgetManager = function (kernel) {
25 var CommManager = function (kernel) {
26 this.widgets = {};
26 this.comms = {};
27 this.widget_types = {widget : Widget};
27 this.targets = {comm : Comm};
28 if (kernel !== undefined) {
28 if (kernel !== undefined) {
29 this.init_kernel(kernel);
29 this.init_kernel(kernel);
30 }
30 }
31 };
31 };
32
32
33 WidgetManager.prototype.init_kernel = function (kernel) {
33 CommManager.prototype.init_kernel = function (kernel) {
34 // connect the kernel, and register message handlers
34 // connect the kernel, and register message handlers
35 this.kernel = kernel;
35 this.kernel = kernel;
36 var msg_types = ['widget_create', 'widget_destroy', 'widget_update'];
36 var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
37 for (var i = 0; i < msg_types.length; i++) {
37 for (var i = 0; i < msg_types.length; i++) {
38 var msg_type = msg_types[i];
38 var msg_type = msg_types[i];
39 kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
39 kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
40 }
40 }
41 };
41 };
42
42
43 WidgetManager.prototype.register_widget_type = function (widget_type, constructor) {
43 CommManager.prototype.register_target = function (target, constructor) {
44 // Register a constructor for a given widget type name
44 // Register a constructor for a given target key
45 this.widget_types[widget_type] = constructor;
45 this.targets[target] = constructor;
46 };
46 };
47
47
48 WidgetManager.prototype.register_widget = function (widget) {
48 CommManager.prototype.register_comm = function (comm) {
49 // Register a widget in the mapping
49 // Register a comm in the mapping
50 this.widgets[widget.widget_id] = widget;
50 this.comms[comm.comm_id] = comm;
51 widget.kernel = this.kernel;
51 comm.kernel = this.kernel;
52 return widget.widget_id;
52 return comm.comm_id;
53 };
53 };
54
54
55 WidgetManager.prototype.unregister_widget = function (widget_id) {
55 CommManager.prototype.unregister_comm = function (comm_id) {
56 // Remove a widget from the mapping
56 // Remove a comm from the mapping
57 delete this.widgets[widget_id];
57 delete this.comms[comm_id];
58 };
58 };
59
59
60 // widget message handlers
60 // comm message handlers
61
61
62 WidgetManager.prototype.widget_create = function (msg) {
62 CommManager.prototype.comm_open = function (msg) {
63 var content = msg.content;
63 var content = msg.content;
64 var constructor = this.widget_types[content.widget_type];
64 var callback = this.targets[content.target];
65 if (constructor === undefined) {
65 if (callback === undefined) {
66 console.log("No such widget type registered: ", content.widget_type);
66 console.log("No such target registered: ", content.target);
67 console.log("Available widget types are: ", this.widget_types);
67 console.log("Available targets are: ", this.targets);
68 return;
68 return;
69 }
69 }
70 var widget = new constructor(content.widget_id);
70 var comm = new Comm(content.comm_id);
71 this.register_widget(widget);
71 this.register_comm(comm);
72 widget.handle_create(content.data);
72 callback(comm);
73
73 comm.handle_open(content.data);
74 this.widgets[content.widget_id] = widget;
75 };
74 };
76
75
77 WidgetManager.prototype.widget_destroy = function (msg) {
76 CommManager.prototype.comm_close = function (msg) {
78 var content = msg.content;
77 var content = msg.content;
79 var widget = this.widgets[content.widget_id];
78 var comm = this.comms[content.comm_id];
80 if (widget === undefined) {
79 if (comm === undefined) {
81 return;
80 return;
82 }
81 }
83 delete this.widgets[content.widget_id];
82 delete this.comms[content.comm_id];
84 widget.handle_destroy(content.data);
83 comm.handle_close(content.data);
85 };
84 };
86
85
87 WidgetManager.prototype.widget_update = function (msg) {
86 CommManager.prototype.comm_msg = function (msg) {
88 var content = msg.content;
87 var content = msg.content;
89 var widget = this.widgets[content.widget_id];
88 var comm = this.comms[content.comm_id];
90 if (widget === undefined) {
89 if (comm === undefined) {
91 return;
90 return;
92 }
91 }
93 widget.handle_update(content.data);
92 comm.handle_msg(content.data);
94 };
93 };
95
94
96 //-----------------------------------------------------------------------
95 //-----------------------------------------------------------------------
97 // Widget base class
96 // Comm base class
98 //-----------------------------------------------------------------------
97 //-----------------------------------------------------------------------
99
98
100 var Widget = function (widget_id) {
99 var Comm = function (comm_id) {
101 this.widget_id = widget_id;
100 this.comm_id = comm_id;
102 this.widget_type = 'widget';
101 this.target = 'comm';
103 };
102 };
104
103
105 // methods for sending messages
104 // methods for sending messages
106 Widget.prototype.create = function (data) {
105 Comm.prototype.open = function (data) {
107 var content = {
106 var content = {
108 widget_id : this.widget_id,
107 comm_id : this.comm_id,
109 widget_type : this.widget_type,
108 target : this.target,
110 data : data || {},
109 data : data || {},
111 };
110 };
112 this.kernel.send_shell_message("widget_create", content);
111 this.kernel.send_shell_message("comm_open", content);
113 };
112 };
114
113
115 Widget.prototype.update = function (data) {
114 Comm.prototype.send = function (data) {
116 var content = {
115 var content = {
117 widget_id : this.widget_id,
116 comm_id : this.comm_id,
118 data : data || {},
117 data : data || {},
119 };
118 };
120 this.kernel.send_shell_message("widget_update", content);
119 return this.kernel.send_shell_message("comm_msg", content);
121 };
120 };
122
121
123 Widget.prototype.destroy = function (data) {
122 Comm.prototype.close = function (data) {
124 var content = {
123 var content = {
125 widget_id : this.widget_id,
124 comm_id : this.comm_id,
126 data : data || {},
125 data : data || {},
127 };
126 };
128 this.kernel.send_shell_message("widget_destroy", content);
127 return this.kernel.send_shell_message("comm_close", content);
129 };
128 };
130
129
131 // methods for handling incoming messages
130 // methods for handling incoming messages
132
131
133 Widget.prototype.handle_create = function (data) {
132 Comm.prototype.handle_open = function (data) {
133 $([this]).trigger("comm_open", data);
134 };
134 };
135
135
136 Widget.prototype.handle_update = function (data) {
136 Comm.prototype.handle_msg = function (data) {
137 $([this]).trigger("comm_msg", data);
137 };
138 };
138
139
139 Widget.prototype.handle_destroy = function (data) {
140 Comm.prototype.handle_close = function (data) {
141 $([this]).trigger("comm_close", data);
140 };
142 };
141
143
142 IPython.WidgetManager = WidgetManager;
144 IPython.CommManager = CommManager;
143 IPython.Widget = Widget;
145 IPython.Comm = Comm;
144
146
145 return IPython;
147 return IPython;
146
148
@@ -68,7 +68,7 function (marked) {
68 IPython.tooltip = new IPython.Tooltip()
68 IPython.tooltip = new IPython.Tooltip()
69 IPython.notification_area = new IPython.NotificationArea('#notification_area')
69 IPython.notification_area = new IPython.NotificationArea('#notification_area')
70 IPython.notification_area.init_notification_widgets();
70 IPython.notification_area.init_notification_widgets();
71 IPython.widget_manager = new IPython.WidgetManager();
71 IPython.comm_manager = new IPython.CommManager();
72
72
73 IPython.layout_manager.do_resize();
73 IPython.layout_manager.do_resize();
74
74
@@ -95,7 +95,7 function (marked) {
95 }
95 }
96 IPython.notebook.set_autosave_interval(IPython.notebook.minimum_autosave_interval);
96 IPython.notebook.set_autosave_interval(IPython.notebook.minimum_autosave_interval);
97 // only do this once
97 // only do this once
98 IPython.widget_manager.init_kernel(IPython.notebook.kernel);
98 IPython.comm_manager.init_kernel(IPython.notebook.kernel);
99 $([IPython.events]).off('notebook_loaded.Notebook', first_load);
99 $([IPython.events]).off('notebook_loaded.Notebook', first_load);
100 };
100 };
101
101
@@ -253,7 +253,7 class="notebook_app"
253 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
253 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
254 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
254 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
255 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
255 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
256 <script src="{{ static_url("notebook/js/widget.js") }}" type="text/javascript" charset="utf-8"></script>
256 <script src="{{ static_url("notebook/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
257 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
257 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
258
258
259 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
259 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
@@ -1,2 +1,2
1 from .manager import *
1 from .manager import *
2 from .widget import *
2 from .comm import *
@@ -168,10 +168,10 class Kernel(Configurable):
168 for msg_type in msg_types:
168 for msg_type in msg_types:
169 self.shell_handlers[msg_type] = getattr(self, msg_type)
169 self.shell_handlers[msg_type] = getattr(self, msg_type)
170
170
171 widget_msg_types = [ 'widget_create', 'widget_update', 'widget_destroy' ]
171 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
172 widget_manager = self.shell.widget_manager
172 comm_manager = self.shell.comm_manager
173 for msg_type in widget_msg_types:
173 for msg_type in comm_msg_types:
174 self.shell_handlers[msg_type] = getattr(widget_manager, msg_type)
174 self.shell_handlers[msg_type] = getattr(comm_manager, msg_type)
175
175
176 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
176 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
177 self.control_handlers = {}
177 self.control_handlers = {}
@@ -49,7 +49,7 from IPython.utils.warn import error
49 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
49 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
50 from IPython.kernel.zmq.datapub import ZMQDataPublisher
50 from IPython.kernel.zmq.datapub import ZMQDataPublisher
51 from IPython.kernel.zmq.session import extract_header
51 from IPython.kernel.zmq.session import extract_header
52 from IPython.kernel.widgets import WidgetManager
52 from IPython.kernel.comm import CommManager
53 from session import Session
53 from session import Session
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
@@ -596,8 +596,8 class ZMQInteractiveShell(InteractiveShell):
596 self.magics_manager.register_alias('ed', 'edit')
596 self.magics_manager.register_alias('ed', 'edit')
597
597
598 def init_widgets(self):
598 def init_widgets(self):
599 self.widget_manager = WidgetManager(shell=self, parent=self)
599 self.comm_manager = CommManager(shell=self, parent=self)
600 self.configurables.append(self.widget_manager)
600 self.configurables.append(self.comm_manager)
601
601
602
602
603 InteractiveShellABC.register(ZMQInteractiveShell)
603 InteractiveShellABC.register(ZMQInteractiveShell)
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now