##// END OF EJS Templates
Remove redundent _handle_close method
Jonathan Frederic -
Show More
@@ -1,449 +1,447 b''
1 """Base Widget class. Allows user to create widgets in the backend that render
1 """Base Widget class. Allows user to create widgets in the backend that render
2 in the IPython notebook frontend.
2 in the IPython notebook frontend.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 from copy import copy
15 from copy import copy
16 from glob import glob
16 from glob import glob
17 import uuid
17 import uuid
18 import sys
18 import sys
19 import os
19 import os
20 import inspect
20 import inspect
21 import types
21 import types
22
22
23 import IPython
23 import IPython
24 from IPython.kernel.comm import Comm
24 from IPython.kernel.comm import Comm
25 from IPython.config import LoggingConfigurable
25 from IPython.config import LoggingConfigurable
26 from IPython.utils.traitlets import Unicode, Dict, List, Instance, Bool
26 from IPython.utils.traitlets import Unicode, Dict, List, Instance, Bool
27 from IPython.display import Javascript, display
27 from IPython.display import Javascript, display
28 from IPython.utils.py3compat import string_types
28 from IPython.utils.py3compat import string_types
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Classes
31 # Classes
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 class Widget(LoggingConfigurable):
33 class Widget(LoggingConfigurable):
34
34
35 # Shared declarations (Class level)
35 # Shared declarations (Class level)
36 _keys = []
36 _keys = []
37 widget_construction_callback = None
37 widget_construction_callback = None
38
38
39 def on_widget_constructed(callback):
39 def on_widget_constructed(callback):
40 """Class method, registers a callback to be called when a widget is
40 """Class method, registers a callback to be called when a widget is
41 constructed. The callback must have the following signature:
41 constructed. The callback must have the following signature:
42 callback(widget)"""
42 callback(widget)"""
43 Widget.widget_construction_callback = callback
43 Widget.widget_construction_callback = callback
44
44
45 def _handle_widget_constructed(widget):
45 def _handle_widget_constructed(widget):
46 """Class method, called when a widget is constructed."""
46 """Class method, called when a widget is constructed."""
47 if Widget.widget_construction_callback is not None and callable(Widget.widget_construction_callback):
47 if Widget.widget_construction_callback is not None and callable(Widget.widget_construction_callback):
48 Widget.widget_construction_callback(widget)
48 Widget.widget_construction_callback(widget)
49
49
50
50
51
51
52 # Public declarations (Instance level)
52 # Public declarations (Instance level)
53 target_name = Unicode('widget', help="""Name of the backbone model
53 target_name = Unicode('widget', help="""Name of the backbone model
54 registered in the frontend to create and sync this widget with.""")
54 registered in the frontend to create and sync this widget with.""")
55 default_view_name = Unicode(help="""Default view registered in the frontend
55 default_view_name = Unicode(help="""Default view registered in the frontend
56 to use to represent the widget.""")
56 to use to represent the widget.""")
57 parent = Instance('IPython.html.widgets.widget.Widget')
57 parent = Instance('IPython.html.widgets.widget.Widget')
58 visible = Bool(True, help="Whether or not the widget is visible.")
58 visible = Bool(True, help="Whether or not the widget is visible.")
59
59
60 def _parent_changed(self, name, old, new):
60 def _parent_changed(self, name, old, new):
61 if self._displayed:
61 if self._displayed:
62 raise Exception('Parent cannot be set because widget has been displayed.')
62 raise Exception('Parent cannot be set because widget has been displayed.')
63 elif new == self:
63 elif new == self:
64 raise Exception('Parent cannot be set to self.')
64 raise Exception('Parent cannot be set to self.')
65 else:
65 else:
66
66
67 # Parent/child association
67 # Parent/child association
68 if new is not None and not self in new._children:
68 if new is not None and not self in new._children:
69 new._children.append(self)
69 new._children.append(self)
70 if old is not None and self in old._children:
70 if old is not None and self in old._children:
71 old._children.remove(self)
71 old._children.remove(self)
72
72
73 # Private/protected declarations
73 # Private/protected declarations
74 _property_lock = (None, None) # Last updated (key, value) from the front-end. Prevents echo.
74 _property_lock = (None, None) # Last updated (key, value) from the front-end. Prevents echo.
75 _css = Dict() # Internal CSS property dict
75 _css = Dict() # Internal CSS property dict
76 _displayed = False
76 _displayed = False
77
77
78
78
79 def __init__(self, **kwargs):
79 def __init__(self, **kwargs):
80 """Public constructor
80 """Public constructor
81
81
82 Parameters
82 Parameters
83 ----------
83 ----------
84 parent : Widget instance (optional)
84 parent : Widget instance (optional)
85 Widget that this widget instance is child of. When the widget is
85 Widget that this widget instance is child of. When the widget is
86 displayed in the frontend, it's corresponding view will be made
86 displayed in the frontend, it's corresponding view will be made
87 child of the parent's view if the parent's view exists already. If
87 child of the parent's view if the parent's view exists already. If
88 the parent's view is displayed, it will automatically display this
88 the parent's view is displayed, it will automatically display this
89 widget's default view as it's child. The default view can be set
89 widget's default view as it's child. The default view can be set
90 via the default_view_name property.
90 via the default_view_name property.
91 """
91 """
92 self._children = []
92 self._children = []
93 self._display_callbacks = []
93 self._display_callbacks = []
94 self._msg_callbacks = []
94 self._msg_callbacks = []
95 super(Widget, self).__init__(**kwargs)
95 super(Widget, self).__init__(**kwargs)
96
96
97 # Register after init to allow default values to be specified
97 # Register after init to allow default values to be specified
98 self.on_trait_change(self._handle_property_changed, self.keys)
98 self.on_trait_change(self._handle_property_changed, self.keys)
99
99
100 Widget._handle_widget_constructed(self)
100 Widget._handle_widget_constructed(self)
101
101
102
102
103 def __del__(self):
103 def __del__(self):
104 """Object disposal"""
104 """Object disposal"""
105 self.close()
105 self.close()
106
106
107
107
108 def close(self):
108 def close(self):
109 """Close method. Closes the widget which closes the underlying comm.
109 """Close method. Closes the widget which closes the underlying comm.
110 When the comm is closed, all of the widget views are automatically
110 When the comm is closed, all of the widget views are automatically
111 removed from the frontend."""
111 removed from the frontend."""
112 self._close_communication()
112 self._close_communication()
113
113
114
114
115 # Properties
115 # Properties
116 def _get_keys(self):
116 def _get_keys(self):
117 keys = ['visible', '_css']
117 keys = ['visible', '_css']
118 keys.extend(self._keys)
118 keys.extend(self._keys)
119 return keys
119 return keys
120 keys = property(_get_keys)
120 keys = property(_get_keys)
121
121
122
122
123 # Event handlers
123 # Event handlers
124 def _handle_msg(self, msg):
124 def _handle_msg(self, msg):
125 """Called when a msg is recieved from the frontend"""
125 """Called when a msg is recieved from the frontend"""
126 data = msg['content']['data']
126 data = msg['content']['data']
127 method = data['method']
127 method = data['method']
128
128
129 # Handle backbone sync methods CREATE, PATCH, and UPDATE
129 # Handle backbone sync methods CREATE, PATCH, and UPDATE
130 if method == 'backbone':
130 if method == 'backbone':
131 if 'sync_method' in data and 'sync_data' in data:
131 if 'sync_method' in data and 'sync_data' in data:
132 sync_method = data['sync_method']
132 sync_method = data['sync_method']
133 sync_data = data['sync_data']
133 sync_data = data['sync_data']
134 self._handle_recieve_state(sync_data) # handles all methods
134 self._handle_recieve_state(sync_data) # handles all methods
135
135
136 # Handle a custom msg from the front-end
136 # Handle a custom msg from the front-end
137 elif method == 'custom':
137 elif method == 'custom':
138 if 'custom_content' in data:
138 if 'custom_content' in data:
139 self._handle_custom_msg(data['custom_content'])
139 self._handle_custom_msg(data['custom_content'])
140
140
141
141
142 def _handle_custom_msg(self, content):
142 def _handle_custom_msg(self, content):
143 """Called when a custom msg is recieved."""
143 """Called when a custom msg is recieved."""
144 for handler in self._msg_callbacks:
144 for handler in self._msg_callbacks:
145 if callable(handler):
145 if callable(handler):
146 argspec = inspect.getargspec(handler)
146 argspec = inspect.getargspec(handler)
147 nargs = len(argspec[0])
147 nargs = len(argspec[0])
148
148
149 # Bound methods have an additional 'self' argument
149 # Bound methods have an additional 'self' argument
150 if isinstance(handler, types.MethodType):
150 if isinstance(handler, types.MethodType):
151 nargs -= 1
151 nargs -= 1
152
152
153 # Call the callback
153 # Call the callback
154 if nargs == 1:
154 if nargs == 1:
155 handler(content)
155 handler(content)
156 elif nargs == 2:
156 elif nargs == 2:
157 handler(self, content)
157 handler(self, content)
158 else:
158 else:
159 raise TypeError('Widget msg callback must ' \
159 raise TypeError('Widget msg callback must ' \
160 'accept 1 or 2 arguments, not %d.' % nargs)
160 'accept 1 or 2 arguments, not %d.' % nargs)
161
161
162
162
163 def _handle_recieve_state(self, sync_data):
163 def _handle_recieve_state(self, sync_data):
164 """Called when a state is recieved from the frontend."""
164 """Called when a state is recieved from the frontend."""
165 # Use _keys instead of keys - Don't get retrieve the css from the client side.
165 # Use _keys instead of keys - Don't get retrieve the css from the client side.
166 for name in self._keys:
166 for name in self._keys:
167 if name in sync_data:
167 if name in sync_data:
168 try:
168 try:
169 self._property_lock = (name, sync_data[name])
169 self._property_lock = (name, sync_data[name])
170 setattr(self, name, sync_data[name])
170 setattr(self, name, sync_data[name])
171 finally:
171 finally:
172 self._property_lock = (None, None)
172 self._property_lock = (None, None)
173
173
174
174
175 def _handle_property_changed(self, name, old, new):
175 def _handle_property_changed(self, name, old, new):
176 """Called when a proeprty has been changed."""
176 """Called when a proeprty has been changed."""
177 # Make sure this isn't information that the front-end just sent us.
177 # Make sure this isn't information that the front-end just sent us.
178 if self._property_lock[0] != name and self._property_lock[1] != new:
178 if self._property_lock[0] != name and self._property_lock[1] != new:
179 # Send new state to frontend
179 # Send new state to frontend
180 self.send_state(key=name)
180 self.send_state(key=name)
181
181
182
182
183 def _handle_displayed(self, view_name, parent=None):
183 def _handle_displayed(self, view_name, parent=None):
184 """Called when a view has been displayed for this widget instance
184 """Called when a view has been displayed for this widget instance
185
185
186 Parameters
186 Parameters
187 ----------
187 ----------
188 view_name: unicode
188 view_name: unicode
189 Name of the view that was displayed.
189 Name of the view that was displayed.
190 parent: Widget instance [optional]
190 parent: Widget instance [optional]
191 Widget that this widget should be displayed as a child of."""
191 Widget that this widget should be displayed as a child of."""
192 for handler in self._display_callbacks:
192 for handler in self._display_callbacks:
193 if callable(handler):
193 if callable(handler):
194 argspec = inspect.getargspec(handler)
194 argspec = inspect.getargspec(handler)
195 nargs = len(argspec[0])
195 nargs = len(argspec[0])
196
196
197 # Bound methods have an additional 'self' argument
197 # Bound methods have an additional 'self' argument
198 if isinstance(handler, types.MethodType):
198 if isinstance(handler, types.MethodType):
199 nargs -= 1
199 nargs -= 1
200
200
201 # Call the callback
201 # Call the callback
202 if nargs == 0:
202 if nargs == 0:
203 handler()
203 handler()
204 elif nargs == 1:
204 elif nargs == 1:
205 handler(self)
205 handler(self)
206 elif nargs == 2:
206 elif nargs == 2:
207 handler(self, view_name)
207 handler(self, view_name)
208 elif nargs == 3:
208 elif nargs == 3:
209 handler(self, view_name, parent)
209 handler(self, view_name, parent)
210 else:
210 else:
211 raise TypeError('Widget display callback must ' \
211 raise TypeError('Widget display callback must ' \
212 'accept 0-2 arguments, not %d.' % nargs)
212 'accept 0-2 arguments, not %d.' % nargs)
213
213
214
214
215 # Public methods
215 # Public methods
216 def send_state(self, key=None):
216 def send_state(self, key=None):
217 """Sends the widget state, or a piece of it, to the frontend.
217 """Sends the widget state, or a piece of it, to the frontend.
218
218
219 Parameters
219 Parameters
220 ----------
220 ----------
221 key : unicode (optional)
221 key : unicode (optional)
222 A single property's name to sync with the frontend.
222 A single property's name to sync with the frontend.
223 """
223 """
224 state = {}
224 state = {}
225
225
226 # If a key is provided, just send the state of that key.
226 # If a key is provided, just send the state of that key.
227 keys = []
227 keys = []
228 if key is None:
228 if key is None:
229 keys.extend(self.keys)
229 keys.extend(self.keys)
230 else:
230 else:
231 keys.append(key)
231 keys.append(key)
232 for key in self.keys:
232 for key in self.keys:
233 try:
233 try:
234 state[key] = getattr(self, key)
234 state[key] = getattr(self, key)
235 except Exception as e:
235 except Exception as e:
236 pass # Eat errors, nom nom nom
236 pass # Eat errors, nom nom nom
237 self._send({"method": "update",
237 self._send({"method": "update",
238 "state": state})
238 "state": state})
239
239
240
240
241 def get_css(self, key, selector=""):
241 def get_css(self, key, selector=""):
242 """Get a CSS property of the widget. Note, this function does not
242 """Get a CSS property of the widget. Note, this function does not
243 actually request the CSS from the front-end; Only properties that have
243 actually request the CSS from the front-end; Only properties that have
244 been set with set_css can be read.
244 been set with set_css can be read.
245
245
246 Parameters
246 Parameters
247 ----------
247 ----------
248 key: unicode
248 key: unicode
249 CSS key
249 CSS key
250 selector: unicode (optional)
250 selector: unicode (optional)
251 JQuery selector used when the CSS key/value was set.
251 JQuery selector used when the CSS key/value was set.
252 """
252 """
253 if selector in self._css and key in self._css[selector]:
253 if selector in self._css and key in self._css[selector]:
254 return self._css[selector][key]
254 return self._css[selector][key]
255 else:
255 else:
256 return None
256 return None
257
257
258
258
259 def set_css(self, *args, **kwargs):
259 def set_css(self, *args, **kwargs):
260 """Set one or more CSS properties of the widget (shared among all of the
260 """Set one or more CSS properties of the widget (shared among all of the
261 views). This function has two signatures:
261 views). This function has two signatures:
262 - set_css(css_dict, [selector=''])
262 - set_css(css_dict, [selector=''])
263 - set_css(key, value, [selector=''])
263 - set_css(key, value, [selector=''])
264
264
265 Parameters
265 Parameters
266 ----------
266 ----------
267 css_dict : dict
267 css_dict : dict
268 CSS key/value pairs to apply
268 CSS key/value pairs to apply
269 key: unicode
269 key: unicode
270 CSS key
270 CSS key
271 value
271 value
272 CSS value
272 CSS value
273 selector: unicode (optional)
273 selector: unicode (optional)
274 JQuery selector to use to apply the CSS key/value.
274 JQuery selector to use to apply the CSS key/value.
275 """
275 """
276 selector = kwargs.get('selector', '')
276 selector = kwargs.get('selector', '')
277
277
278 # Signature 1: set_css(css_dict, [selector=''])
278 # Signature 1: set_css(css_dict, [selector=''])
279 if len(args) == 1:
279 if len(args) == 1:
280 if isinstance(args[0], dict):
280 if isinstance(args[0], dict):
281 for (key, value) in args[0].items():
281 for (key, value) in args[0].items():
282 self.set_css(key, value, selector=selector)
282 self.set_css(key, value, selector=selector)
283 else:
283 else:
284 raise Exception('css_dict must be a dict.')
284 raise Exception('css_dict must be a dict.')
285
285
286 # Signature 2: set_css(key, value, [selector=''])
286 # Signature 2: set_css(key, value, [selector=''])
287 elif len(args) == 2 or len(args) == 3:
287 elif len(args) == 2 or len(args) == 3:
288
288
289 # Selector can be a positional arg if it's the 3rd value
289 # Selector can be a positional arg if it's the 3rd value
290 if len(args) == 3:
290 if len(args) == 3:
291 selector = args[2]
291 selector = args[2]
292 if selector not in self._css:
292 if selector not in self._css:
293 self._css[selector] = {}
293 self._css[selector] = {}
294
294
295 # Only update the property if it has changed.
295 # Only update the property if it has changed.
296 key = args[0]
296 key = args[0]
297 value = args[1]
297 value = args[1]
298 if not (key in self._css[selector] and value in self._css[selector][key]):
298 if not (key in self._css[selector] and value in self._css[selector][key]):
299 self._css[selector][key] = value
299 self._css[selector][key] = value
300 self.send_state('_css') # Send new state to client.
300 self.send_state('_css') # Send new state to client.
301 else:
301 else:
302 raise Exception('set_css only accepts 1-3 arguments')
302 raise Exception('set_css only accepts 1-3 arguments')
303
303
304
304
305 def add_class(self, class_name, selector=""):
305 def add_class(self, class_name, selector=""):
306 """Add class[es] to a DOM element
306 """Add class[es] to a DOM element
307
307
308 Parameters
308 Parameters
309 ----------
309 ----------
310 class_name: unicode
310 class_name: unicode
311 Class name(s) to add to the DOM element(s). Multiple class names
311 Class name(s) to add to the DOM element(s). Multiple class names
312 must be space separated.
312 must be space separated.
313 selector: unicode (optional)
313 selector: unicode (optional)
314 JQuery selector to select the DOM element(s) that the class(es) will
314 JQuery selector to select the DOM element(s) that the class(es) will
315 be added to.
315 be added to.
316 """
316 """
317 self._send({"method": "add_class",
317 self._send({"method": "add_class",
318 "class_list": class_name,
318 "class_list": class_name,
319 "selector": selector})
319 "selector": selector})
320
320
321
321
322 def remove_class(self, class_name, selector=""):
322 def remove_class(self, class_name, selector=""):
323 """Remove class[es] from a DOM element
323 """Remove class[es] from a DOM element
324
324
325 Parameters
325 Parameters
326 ----------
326 ----------
327 class_name: unicode
327 class_name: unicode
328 Class name(s) to remove from the DOM element(s). Multiple class
328 Class name(s) to remove from the DOM element(s). Multiple class
329 names must be space separated.
329 names must be space separated.
330 selector: unicode (optional)
330 selector: unicode (optional)
331 JQuery selector to select the DOM element(s) that the class(es) will
331 JQuery selector to select the DOM element(s) that the class(es) will
332 be removed from.
332 be removed from.
333 """
333 """
334 self._send({"method": "remove_class",
334 self._send({"method": "remove_class",
335 "class_list": class_name,
335 "class_list": class_name,
336 "selector": selector})
336 "selector": selector})
337
337
338
338
339 def send(self, content):
339 def send(self, content):
340 """Sends a custom msg to the widget model in the front-end.
340 """Sends a custom msg to the widget model in the front-end.
341
341
342 Parameters
342 Parameters
343 ----------
343 ----------
344 content : dict
344 content : dict
345 Content of the message to send.
345 Content of the message to send.
346 """
346 """
347 self._send({"method": "custom",
347 self._send({"method": "custom",
348 "custom_content": content})
348 "custom_content": content})
349
349
350
350
351 def on_msg(self, callback, remove=False):
351 def on_msg(self, callback, remove=False):
352 """Register a callback for when a custom msg is recieved from the front-end
352 """Register a callback for when a custom msg is recieved from the front-end
353
353
354 Parameters
354 Parameters
355 ----------
355 ----------
356 callback: method handler
356 callback: method handler
357 Can have a signature of:
357 Can have a signature of:
358 - callback(content)
358 - callback(content)
359 - callback(sender, content)
359 - callback(sender, content)
360 remove: bool
360 remove: bool
361 True if the callback should be unregistered."""
361 True if the callback should be unregistered."""
362 if remove and callback in self._msg_callbacks:
362 if remove and callback in self._msg_callbacks:
363 self._msg_callbacks.remove(callback)
363 self._msg_callbacks.remove(callback)
364 elif not remove and not callback in self._msg_callbacks:
364 elif not remove and not callback in self._msg_callbacks:
365 self._msg_callbacks.append(callback)
365 self._msg_callbacks.append(callback)
366
366
367
367
368 def on_displayed(self, callback, remove=False):
368 def on_displayed(self, callback, remove=False):
369 """Register a callback to be called when the widget has been displayed
369 """Register a callback to be called when the widget has been displayed
370
370
371 Parameters
371 Parameters
372 ----------
372 ----------
373 callback: method handler
373 callback: method handler
374 Can have a signature of:
374 Can have a signature of:
375 - callback()
375 - callback()
376 - callback(sender)
376 - callback(sender)
377 - callback(sender, view_name)
377 - callback(sender, view_name)
378 - callback(sender, view_name, parent)
378 - callback(sender, view_name, parent)
379 remove: bool
379 remove: bool
380 True if the callback should be unregistered."""
380 True if the callback should be unregistered."""
381 if remove and callback in self._display_callbacks:
381 if remove and callback in self._display_callbacks:
382 self._display_callbacks.remove(callback)
382 self._display_callbacks.remove(callback)
383 elif not remove and not callback in self._display_callbacks:
383 elif not remove and not callback in self._display_callbacks:
384 self._display_callbacks.append(callback)
384 self._display_callbacks.append(callback)
385
385
386
386
387 # Support methods
387 # Support methods
388 def _repr_widget_(self, view_name=None):
388 def _repr_widget_(self, view_name=None):
389 """Function that is called when `IPython.display.display` is called on
389 """Function that is called when `IPython.display.display` is called on
390 the widget.
390 the widget.
391
391
392 Parameters
392 Parameters
393 ----------
393 ----------
394 view_name: unicode (optional)
394 view_name: unicode (optional)
395 View to display in the frontend. Overrides default_view_name."""
395 View to display in the frontend. Overrides default_view_name."""
396 if not view_name:
396 if not view_name:
397 view_name = self.default_view_name
397 view_name = self.default_view_name
398
398
399 # Create a communication.
399 # Create a communication.
400 self._open_communication()
400 self._open_communication()
401
401
402 # Make sure model is syncronized
402 # Make sure model is syncronized
403 self.send_state()
403 self.send_state()
404
404
405 # Show view.
405 # Show view.
406 if self.parent is None or self.parent._comm is None:
406 if self.parent is None or self.parent._comm is None:
407 self._send({"method": "display", "view_name": view_name})
407 self._send({"method": "display", "view_name": view_name})
408 self._handle_displayed(view_name)
408 self._handle_displayed(view_name)
409 else:
409 else:
410 self._send({"method": "display",
410 self._send({"method": "display",
411 "view_name": view_name,
411 "view_name": view_name,
412 "parent": self.parent._comm.comm_id})
412 "parent": self.parent._comm.comm_id})
413 self._handle_displayed(view_name, self.parent)
413 self._handle_displayed(view_name, self.parent)
414 self._displayed = True
414 self._displayed = True
415
415
416 # Now display children if any.
416 # Now display children if any.
417 for child in self._children:
417 for child in self._children:
418 if child != self:
418 if child != self:
419 child._repr_widget_()
419 child._repr_widget_()
420 return None
420 return None
421
421
422
422
423 def _open_communication(self):
423 def _open_communication(self):
424 """Opens a communication with the front-end."""
424 """Opens a communication with the front-end."""
425 # Create a comm.
425 # Create a comm.
426 if not hasattr(self, '_comm') or self._comm is None:
426 if not hasattr(self, '_comm') or self._comm is None:
427 self._comm = Comm(target_name=self.target_name)
427 self._comm = Comm(target_name=self.target_name)
428 self._comm.on_msg(self._handle_msg)
428 self._comm.on_msg(self._handle_msg)
429 self._comm.on_close(self._handle_close)
429 self._comm.on_close(self._close_communication)
430
431
432 def _handle_close(self):
433 """Called when the comm is closed by the front-end."""
434 self._close_communication()
435
430
436
431
437 def _close_communication(self):
432 def _close_communication(self):
438 """Closes a communication with the front-end."""
433 """Closes a communication with the front-end."""
439 if hasattr(self, '_comm') and self._comm is not None:
434 if hasattr(self, '_comm') and self._comm is not None:
435 try:
440 self._comm.close()
436 self._comm.close()
437 finally:
438 self._comm = None
441
439
442
440
443 def _send(self, msg):
441 def _send(self, msg):
444 """Sends a message to the model in the front-end"""
442 """Sends a message to the model in the front-end"""
445 if hasattr(self, '_comm') and self._comm is not None:
443 if hasattr(self, '_comm') and self._comm is not None:
446 self._comm.send(msg)
444 self._comm.send(msg)
447 return True
445 return True
448 else:
446 else:
449 return False
447 return False
General Comments 0
You need to be logged in to leave comments. Login now