##// END OF EJS Templates
hook up output for comm messages
MinRK -
Show More
@@ -1,173 +1,173
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Comm and CommManager bases
9 // Comm and CommManager bases
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * Base Comm classes
12 * Base Comm classes
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule comm
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 // CommManager class
22 // CommManager class
23 //-----------------------------------------------------------------------
23 //-----------------------------------------------------------------------
24
24
25 var CommManager = function (kernel) {
25 var CommManager = function (kernel) {
26 this.comms = {};
26 this.comms = {};
27 this.targets = {comm : Comm};
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 CommManager.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 = ['comm_open', 'comm_msg', 'comm_close'];
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 CommManager.prototype.register_target = function (target, constructor) {
43 CommManager.prototype.register_target = function (target, constructor) {
44 // Register a constructor for a given target key
44 // Register a constructor for a given target key
45 this.targets[target] = constructor;
45 this.targets[target] = constructor;
46 };
46 };
47
47
48 CommManager.prototype.register_comm = function (comm) {
48 CommManager.prototype.register_comm = function (comm) {
49 // Register a comm in the mapping
49 // Register a comm in the mapping
50 this.comms[comm.comm_id] = comm;
50 this.comms[comm.comm_id] = comm;
51 comm.kernel = this.kernel;
51 comm.kernel = this.kernel;
52 return comm.comm_id;
52 return comm.comm_id;
53 };
53 };
54
54
55 CommManager.prototype.unregister_comm = function (comm_id) {
55 CommManager.prototype.unregister_comm = function (comm_id) {
56 // Remove a comm from the mapping
56 // Remove a comm from the mapping
57 delete this.comms[comm_id];
57 delete this.comms[comm_id];
58 };
58 };
59
59
60 // comm message handlers
60 // comm message handlers
61
61
62 CommManager.prototype.comm_open = function (msg) {
62 CommManager.prototype.comm_open = function (msg) {
63 var content = msg.content;
63 var content = msg.content;
64 var callback = this.targets[content.target];
64 var callback = this.targets[content.target];
65 if (callback === undefined) {
65 if (callback === undefined) {
66 console.log("No such target registered: ", content.target);
66 console.log("No such target registered: ", content.target);
67 console.log("Available targets are: ", this.targets);
67 console.log("Available targets are: ", this.targets);
68 return;
68 return;
69 }
69 }
70 var comm = new Comm(content.comm_id);
70 var comm = new Comm(content.comm_id);
71 this.register_comm(comm);
71 this.register_comm(comm);
72 callback(comm);
72 callback(comm);
73 comm.handle_open(msg);
73 comm.handle_open(msg);
74 };
74 };
75
75
76 CommManager.prototype.comm_close = function (msg) {
76 CommManager.prototype.comm_close = function (msg) {
77 var content = msg.content;
77 var content = msg.content;
78 var comm = this.comms[content.comm_id];
78 var comm = this.comms[content.comm_id];
79 if (comm === undefined) {
79 if (comm === undefined) {
80 return;
80 return;
81 }
81 }
82 delete this.comms[content.comm_id];
82 delete this.comms[content.comm_id];
83 comm.handle_close(msg);
83 comm.handle_close(msg);
84 };
84 };
85
85
86 CommManager.prototype.comm_msg = function (msg) {
86 CommManager.prototype.comm_msg = function (msg) {
87 var content = msg.content;
87 var content = msg.content;
88 var comm = this.comms[content.comm_id];
88 var comm = this.comms[content.comm_id];
89 if (comm === undefined) {
89 if (comm === undefined) {
90 return;
90 return;
91 }
91 }
92 comm.handle_msg(msg);
92 comm.handle_msg(msg);
93 };
93 };
94
94
95 //-----------------------------------------------------------------------
95 //-----------------------------------------------------------------------
96 // Comm base class
96 // Comm base class
97 //-----------------------------------------------------------------------
97 //-----------------------------------------------------------------------
98
98
99 var Comm = function (comm_id, target) {
99 var Comm = function (comm_id, target) {
100 this.comm_id = comm_id;
100 this.comm_id = comm_id || new IPython.utils.uuid();
101 this.target = target || 'comm';
101 this.target = target || 'comm';
102 this._msg_callback = this._open_callback = this._close_callback = null;
102 this._msg_callback = this._open_callback = this._close_callback = null;
103 };
103 };
104
104
105 // methods for sending messages
105 // methods for sending messages
106 Comm.prototype.open = function (data) {
106 Comm.prototype.open = function (data, callbacks) {
107 var content = {
107 var content = {
108 comm_id : this.comm_id,
108 comm_id : this.comm_id,
109 target : this.target,
109 target : this.target,
110 data : data || {},
110 data : data || {},
111 };
111 };
112 this.kernel.send_shell_message("comm_open", content);
112 return this.kernel.send_shell_message("comm_open", content, callbacks);
113 };
113 };
114
114
115 Comm.prototype.send = function (data) {
115 Comm.prototype.send = function (data, callbacks) {
116 var content = {
116 var content = {
117 comm_id : this.comm_id,
117 comm_id : this.comm_id,
118 data : data || {},
118 data : data || {},
119 };
119 };
120 return this.kernel.send_shell_message("comm_msg", content);
120 return this.kernel.send_shell_message("comm_msg", content, callbacks);
121 };
121 };
122
122
123 Comm.prototype.close = function (data) {
123 Comm.prototype.close = function (data, callbacks) {
124 var content = {
124 var content = {
125 comm_id : this.comm_id,
125 comm_id : this.comm_id,
126 data : data || {},
126 data : data || {},
127 };
127 };
128 return this.kernel.send_shell_message("comm_close", content);
128 return this.kernel.send_shell_message("comm_close", content, callbacks);
129 };
129 };
130
130
131 // methods for registering callbacks for incoming messages
131 // methods for registering callbacks for incoming messages
132 Comm.prototype._register_callback = function (key, callback) {
132 Comm.prototype._register_callback = function (key, callback) {
133 this['_' + key + '_callback'] = callback;
133 this['_' + key + '_callback'] = callback;
134 };
134 };
135
135
136 Comm.prototype.on_open = function (callback) {
136 Comm.prototype.on_open = function (callback) {
137 this._register_callback('open', callback);
137 this._register_callback('open', callback);
138 };
138 };
139
139
140 Comm.prototype.on_msg = function (callback) {
140 Comm.prototype.on_msg = function (callback) {
141 this._register_callback('msg', callback);
141 this._register_callback('msg', callback);
142 };
142 };
143
143
144 Comm.prototype.on_close = function (callback) {
144 Comm.prototype.on_close = function (callback) {
145 this._register_callback('close', callback);
145 this._register_callback('close', callback);
146 };
146 };
147
147
148 // methods for handling incoming messages
148 // methods for handling incoming messages
149
149
150 Comm.prototype._maybe_callback = function (key, msg) {
150 Comm.prototype._maybe_callback = function (key, msg) {
151 var callback = this['_' + key + '_callback'];
151 var callback = this['_' + key + '_callback'];
152 if (callback) callback(msg);
152 if (callback) callback(msg);
153 };
153 };
154
154
155 Comm.prototype.handle_open = function (msg) {
155 Comm.prototype.handle_open = function (msg) {
156 this._maybe_callback('open', msg);
156 this._maybe_callback('open', msg);
157 };
157 };
158
158
159 Comm.prototype.handle_msg = function (msg) {
159 Comm.prototype.handle_msg = function (msg) {
160 this._maybe_callback('msg', msg);
160 this._maybe_callback('msg', msg);
161 };
161 };
162
162
163 Comm.prototype.handle_close = function (msg) {
163 Comm.prototype.handle_close = function (msg) {
164 this._maybe_callback('close', msg);
164 this._maybe_callback('close', msg);
165 };
165 };
166
166
167 IPython.CommManager = CommManager;
167 IPython.CommManager = CommManager;
168 IPython.Comm = Comm;
168 IPython.Comm = Comm;
169
169
170 return IPython;
170 return IPython;
171
171
172 }(IPython));
172 }(IPython));
173
173
@@ -1,142 +1,163
1 """Base class to manage comms"""
1 """Base class to manage comms"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
4 # Copyright (C) 2013 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import sys
15
14 from IPython.config import LoggingConfigurable
16 from IPython.config import LoggingConfigurable
15 from IPython.core.prompts import LazyEvaluate
17 from IPython.core.prompts import LazyEvaluate
16 from IPython.core.getipython import get_ipython
18 from IPython.core.getipython import get_ipython
17
19
18 from IPython.utils.importstring import import_item
20 from IPython.utils.importstring import import_item
19 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
21 from IPython.utils.traitlets import Instance, Unicode, Dict, Any
20
22
21 from .comm import Comm
23 from .comm import Comm
22
24
23 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
24 # Code
26 # Code
25 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
26
28
27 def lazy_keys(dikt):
29 def lazy_keys(dikt):
28 """Return lazy-evaluated string representation of a dictionary's keys
30 """Return lazy-evaluated string representation of a dictionary's keys
29
31
30 Key list is only constructed if it will actually be used.
32 Key list is only constructed if it will actually be used.
31 Used for debug-logging.
33 Used for debug-logging.
32 """
34 """
33 return LazyEvaluate(lambda d: list(d.keys()))
35 return LazyEvaluate(lambda d: list(d.keys()))
34
36
35
37
38 def with_output(method):
39 """method decorator for ensuring output is handled properly in a message handler
40
41 - sets parent header before entering the method
42 - flushes stdout/stderr after
43 """
44 def method_with_output(self, stream, ident, msg):
45 self.shell.set_parent(msg['header'])
46 try:
47 return method(self, stream, ident, msg)
48 finally:
49 sys.stdout.flush()
50 sys.stderr.flush()
51
52 return method_with_output
53
54
36 class CommManager(LoggingConfigurable):
55 class CommManager(LoggingConfigurable):
37 """Manager for Comms in the Kernel"""
56 """Manager for Comms in the Kernel"""
38
57
39 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
58 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
40 def _shell_default(self):
59 def _shell_default(self):
41 return get_ipython()
60 return get_ipython()
42 iopub_socket = Any()
61 iopub_socket = Any()
43 def _iopub_socket_default(self):
62 def _iopub_socket_default(self):
44 return self.shell.kernel.iopub_socket
63 return self.shell.kernel.iopub_socket
45 session = Instance('IPython.kernel.zmq.session.Session')
64 session = Instance('IPython.kernel.zmq.session.Session')
46 def _session_default(self):
65 def _session_default(self):
47 if self.shell is None:
66 if self.shell is None:
48 return
67 return
49 return self.shell.kernel.session
68 return self.shell.kernel.session
50
69
51 comms = Dict()
70 comms = Dict()
52 targets = Dict()
71 targets = Dict()
53
72
54 # Public APIs
73 # Public APIs
55
74
56 def register_target(self, target, f):
75 def register_target(self, target, f):
57 """Register a callable f for a given target
76 """Register a callable f for a given target
58
77
59 f will be called with a Comm object as its only argument
78 f will be called with a Comm object as its only argument
60 when a comm_open message is received with `target`.
79 when a comm_open message is received with `target`.
61
80
62 f can be a Python callable or an import string for one.
81 f can be a Python callable or an import string for one.
63 """
82 """
64 if isinstance(f, basestring):
83 if isinstance(f, basestring):
65 f = import_item(f)
84 f = import_item(f)
66
85
67 self.targets[target] = f
86 self.targets[target] = f
68
87
69 def register_comm(self, comm):
88 def register_comm(self, comm):
70 """Register a new comm"""
89 """Register a new comm"""
71 comm_id = comm.comm_id
90 comm_id = comm.comm_id
72 comm.shell = self.shell
91 comm.shell = self.shell
73 comm.iopub_socket = self.iopub_socket
92 comm.iopub_socket = self.iopub_socket
74 self.comms[comm_id] = comm
93 self.comms[comm_id] = comm
75 return comm_id
94 return comm_id
76
95
77 def unregister_comm(self, comm_id):
96 def unregister_comm(self, comm_id):
78 """Unregister a comm, and close its counterpart"""
97 """Unregister a comm, and close its counterpart"""
79 # unlike get_comm, this should raise a KeyError
98 # unlike get_comm, this should raise a KeyError
80 comm = self.comms.pop(comm_id)
99 comm = self.comms.pop(comm_id)
81 comm.close()
100 comm.close()
82
101
83 def get_comm(self, comm_id):
102 def get_comm(self, comm_id):
84 """Get a comm with a particular id
103 """Get a comm with a particular id
85
104
86 Returns the comm if found, otherwise None.
105 Returns the comm if found, otherwise None.
87
106
88 This will not raise an error,
107 This will not raise an error,
89 it will log messages if the comm cannot be found.
108 it will log messages if the comm cannot be found.
90 """
109 """
91 if comm_id not in self.comms:
110 if comm_id not in self.comms:
92 self.log.error("No such comm: %s", comm_id)
111 self.log.error("No such comm: %s", comm_id)
93 self.log.debug("Current comms: %s", lazy_keys(self.comms))
112 self.log.debug("Current comms: %s", lazy_keys(self.comms))
94 return
113 return
95 # call, because we store weakrefs
114 # call, because we store weakrefs
96 comm = self.comms[comm_id]
115 comm = self.comms[comm_id]
97 return comm
116 return comm
98
117
99 # Message handlers
118 # Message handlers
100
119 @with_output
101 def comm_open(self, stream, ident, msg):
120 def comm_open(self, stream, ident, msg):
102 """Handler for comm_open messages"""
121 """Handler for comm_open messages"""
103 content = msg['content']
122 content = msg['content']
104 comm_id = content['comm_id']
123 comm_id = content['comm_id']
105 target = content['target']
124 target = content['target']
106 callback = self.targets.get(target, None)
125 callback = self.targets.get(target, None)
107 comm = Comm(comm_id=comm_id,
126 comm = Comm(comm_id=comm_id,
108 shell=self.shell,
127 shell=self.shell,
109 iopub_socket=self.iopub_socket,
128 iopub_socket=self.iopub_socket,
110 primary=False,
129 primary=False,
111 )
130 )
112 if callback is None:
131 if callback is None:
113 self.log.error("No such comm target registered: %s", target)
132 self.log.error("No such comm target registered: %s", target)
114 comm.close()
133 comm.close()
115 return
134 return
116 callback(comm)
135 callback(comm)
117 comm.handle_open(msg)
136 comm.handle_open(msg)
118 self.register_comm(comm)
137 self.register_comm(comm)
119
138
139 @with_output
120 def comm_msg(self, stream, ident, msg):
140 def comm_msg(self, stream, ident, msg):
121 """Handler for comm_msg messages"""
141 """Handler for comm_msg messages"""
122 content = msg['content']
142 content = msg['content']
123 comm_id = content['comm_id']
143 comm_id = content['comm_id']
124 comm = self.get_comm(comm_id)
144 comm = self.get_comm(comm_id)
125 if comm is None:
145 if comm is None:
126 # no such comm
146 # no such comm
127 return
147 return
128 comm.handle_msg(msg)
148 comm.handle_msg(msg)
129
149
150 @with_output
130 def comm_close(self, stream, ident, msg):
151 def comm_close(self, stream, ident, msg):
131 """Handler for comm_close messages"""
152 """Handler for comm_close messages"""
132 content = msg['content']
153 content = msg['content']
133 comm_id = content['comm_id']
154 comm_id = content['comm_id']
134 comm = self.get_comm(comm_id)
155 comm = self.get_comm(comm_id)
135 if comm is None:
156 if comm is None:
136 # no such comm
157 # no such comm
137 return
158 return
138 del self.comms[comm_id]
159 del self.comms[comm_id]
139 comm.handle_close(msg)
160 comm.handle_close(msg)
140
161
141
162
142 __all__ = ['CommManager']
163 __all__ = ['CommManager']
General Comments 0
You need to be logged in to leave comments. Login now