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