Skip to content

Commit 80ce43d

Browse files
committed
WIP consolidating logic for property lock.
1 parent f404a48 commit 80ce43d

File tree

1 file changed

+40
-27
lines changed
  • python/ipywidgets/ipywidgets/widgets

1 file changed

+40
-27
lines changed

python/ipywidgets/ipywidgets/widgets/widget.py

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -512,34 +512,47 @@ def send_state(self, key=None):
512512
A single property's name or iterable of property names to sync with the front-end.
513513
"""
514514
state = self.get_state(key=key)
515-
if len(state) > 0:
516-
if JUPYTER_WIDGETS_ECHO:
517-
echo_state = {}
518-
if self._updated_attrs_from_frontend:
519-
for attr in self._updated_attrs_from_frontend:
520-
echo_state[attr] = state[attr]
521-
del state[attr]
522-
self._updated_attrs_from_frontend = None
523-
state, buffer_paths, buffers = _remove_buffers(state)
524-
echo_state, echo_buffer_paths, echo_buffers = _remove_buffers(echo_state)
525-
msg = {'method': 'update', 'state': state, 'buffer_paths': buffer_paths}
526-
if echo_state or echo_buffer_paths:
527-
msg['echo_state'] = echo_state
528-
msg['echo_buffer_paths'] = echo_buffer_paths
529-
buffers += echo_buffers
530-
self._send(msg, buffers=buffers)
531-
return
532-
533-
# TODO: _property_lock is our understanding of what the frontend thinks values are
534-
# TODO: it is based on what we've sent the frontend
535-
if self._property_lock: # we need to keep this dict up to date with the front-end values
536-
for name, value in state.items():
537-
if name in self._property_lock:
538-
self._property_lock[name] = value
539-
state, buffer_paths, buffers = _remove_buffers(state)
540-
msg = {'method': 'update', 'state': state, 'buffer_paths': buffer_paths}
541-
self._send(msg, buffers=buffers)
515+
if len(state) == 0:
516+
return
542517

518+
# For any values that are currently locked (i.e., we are not echoing,
519+
# and we are currently processing an update for), we need to update our
520+
# notion of what the frontend value is.
521+
522+
# TODO: does this handle the case where we get an update from the
523+
# frontend, in the middle of this we update the value *and send it*, and
524+
# then at the end we have to evaluate whether to send an echo message.
525+
# We need to send an echo message at some point so the originator can unblock
526+
# other echo messages, and we don't want to send the same data twice. So probably
527+
# the first time we send an update for an attribute back, we need to send it as an
528+
# echo, and record that we've already sent it. So perhaps we just need to keep
529+
# track of what echos we need to send, and we send at the end whatever echos still
530+
# need to be sent.
531+
532+
# Sending echos at the end may send updates out of order, i.e., we may send
533+
# some updates in the middle, then send echos at the end. perhaps we should immediately
534+
# send echos just as we start processing the message?
535+
if self._property_lock:
536+
for name, value in state.items():
537+
if name in self._property_lock:
538+
self._property_lock[name] = value
539+
540+
541+
echo_state = {}
542+
if self._updated_attrs_from_frontend:
543+
for attr in self._updated_attrs_from_frontend:
544+
echo_state[attr] = state[attr]
545+
del state[attr]
546+
self._updated_attrs_from_frontend = None
547+
state, buffer_paths, buffers = _remove_buffers(state)
548+
echo_state, echo_buffer_paths, echo_buffers = _remove_buffers(echo_state)
549+
msg = {'method': 'update', 'state': state, 'buffer_paths': buffer_paths}
550+
if echo_state or echo_buffer_paths:
551+
msg['echo_state'] = echo_state
552+
msg['echo_buffer_paths'] = echo_buffer_paths
553+
buffers += echo_buffers
554+
self._send(msg, buffers=buffers)
555+
return
543556

544557
def get_state(self, key=None, drop_defaults=False):
545558
"""Gets the widget state, or a piece of it.

0 commit comments

Comments
 (0)