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