Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits

Sometimes for consistency or efficiency purposes, it makes sense to update
a group of properties all at once.  This context manager makes this possible.

We also fix a bug where send_state was not passing the key on to get_state.
pull/37/head
Jason Grout 12 years ago
parent e60f8bdda1
commit af26d9cc24

@ -13,11 +13,12 @@ in the IPython notebook front-end.
# Imports
#-----------------------------------------------------------------------------
from contextlib import contextmanager
import collections
from IPython.core.getipython import get_ipython
from IPython.kernel.comm import Comm
from IPython.config import LoggingConfigurable
from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple, Int
from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple, Int, Set
from IPython.utils.py3compat import string_types
#-----------------------------------------------------------------------------
@ -110,7 +111,8 @@ class Widget(LoggingConfigurable):
return [name for name in self.traits(sync=True)]
_property_lock = Tuple((None, None))
_send_state_lock = Int(0)
_states_to_send = Set(allow_none=False)
_display_callbacks = Instance(CallbackDispatcher, ())
_msg_callbacks = Instance(CallbackDispatcher, ())
@ -174,12 +176,12 @@ class Widget(LoggingConfigurable):
Parameters
----------
key : unicode (optional)
A single property's name to sync with the front-end.
key : unicode, or iterable (optional)
A single property's name or iterable of property names to sync with the front-end.
"""
self._send({
"method" : "update",
"state" : self.get_state()
"state" : self.get_state(key=key)
})
def get_state(self, key=None):
@ -187,10 +189,17 @@ class Widget(LoggingConfigurable):
Parameters
----------
key : unicode (optional)
A single property's name to get.
key : unicode or iterable (optional)
A single property's name or iterable of property names to get.
"""
keys = self.keys if key is None else [key]
if key is None:
keys = self.keys
elif isinstance(key, string_types):
keys = [key]
elif isinstance(key, collections.Iterable):
keys = key
else:
raise ValueError("key must be a string, an iterable of keys, or None")
state = {}
for k in keys:
f = self.trait_metadata(k, 'to_json')
@ -255,10 +264,26 @@ class Widget(LoggingConfigurable):
finally:
self._property_lock = (None, None)
@contextmanager
def hold_sync(self):
"""Hold syncing any state until the context manager is released"""
# We increment a value so that this can be nested. Syncing will happen when
# all levels have been released.
self._send_state_lock += 1
try:
yield
finally:
self._send_state_lock -=1
if self._send_state_lock == 0:
self.send_state(self._states_to_send)
self._states_to_send.clear()
def _should_send_property(self, key, value):
"""Check the property lock (property_lock)"""
return key != self._property_lock[0] or \
value != self._property_lock[1]
if self._send_state_lock > 0:
self._states_to_send.add(key)
return False
return key != self._property_lock[0] or value != self._property_lock[1]
# Event handlers
@_show_traceback

Loading…
Cancel
Save