@@ -262,53 +262,9 @@ def set(self, value: dict) -> None:
262262 cell_id = new_cell .get ("id" )
263263 if cell_id and (old_ycell := old_ycells_by_id .get (cell_id )):
264264 old_cell = self ._cell_to_py (old_ycell )
265- updated_granularly = True
266- if old_cell != new_cell :
267- # attempt to update cell granularly
268- old_keys = set (old_cell .keys ())
269- new_keys = set (new_cell .keys ())
270-
271- shared_keys = old_keys & new_keys
272- removed_keys = old_keys - new_keys
273- added_keys = new_keys - old_keys
274-
275- for key in shared_keys :
276- if old_cell [key ] != new_cell [key ]:
277- if key == "output" and value :
278- # outputs require complex handling - some have Text type nested;
279- # for now skip creating them; clearing all outputs is fine
280- updated_granularly = False
281-
282- if key in _CELL_KEY_TYPE_MAP :
283- kind = _CELL_KEY_TYPE_MAP [key ]
284- value = new_cell [key ]
285- if kind == Text :
286- old : Text = old_ycell [key ]
287- old .clear ()
288- old .insert (0 , value )
289- elif kind == Array :
290- old : Array = old_ycell [key ]
291- old .clear ()
292- old .extend (value )
293- elif kind == Map :
294- old : Map = old_ycell [key ]
295- old .clear ()
296- for k , v in value .items ():
297- old [k ] = v
298- else :
299- old_ycell [key ] = new_cell [key ]
300-
301- for key in removed_keys :
302- del old_ycell [key ]
303-
304- for key in added_keys :
305- if key in _CELL_KEY_TYPE_MAP :
306- # we hard-reload cells when keys that require nested types get added
307- # to allow the frontend to connect observers; this could be changed
308- # in the future, once frontends learn how to observe all changes
309- updated_granularly = False
310- else :
311- old_ycell [key ] = new_cell [key ]
265+ updated_granularly = self ._update_cell (
266+ old_cell = old_cell , new_cell = new_cell , old_ycell = old_ycell
267+ )
312268
313269 if updated_granularly :
314270 new_cell_list .append (old_cell )
@@ -374,3 +330,53 @@ def observe(self, callback: Callable[[str, Any], None]) -> None:
374330 self ._subscriptions [self ._ystate ] = self ._ystate .observe (partial (callback , "state" ))
375331 self ._subscriptions [self ._ymeta ] = self ._ymeta .observe_deep (partial (callback , "meta" ))
376332 self ._subscriptions [self ._ycells ] = self ._ycells .observe_deep (partial (callback , "cells" ))
333+
334+ def _update_cell (self , old_cell : dict , new_cell : dict , old_ycell : Map ) -> bool :
335+ if old_cell == new_cell :
336+ return True
337+ # attempt to update cell granularly
338+ old_keys = set (old_cell .keys ())
339+ new_keys = set (new_cell .keys ())
340+
341+ shared_keys = old_keys & new_keys
342+ removed_keys = old_keys - new_keys
343+ added_keys = new_keys - old_keys
344+
345+ for key in shared_keys :
346+ if old_cell [key ] != new_cell [key ]:
347+ value = new_cell [key ]
348+ if key == "output" and value :
349+ # outputs require complex handling - some have Text type nested;
350+ # for now skip creating them; clearing all outputs is fine
351+ return False
352+
353+ if key in _CELL_KEY_TYPE_MAP :
354+ kind = _CELL_KEY_TYPE_MAP [key ]
355+ if kind == Text and value :
356+ old : Text = old_ycell [key ]
357+ old .clear ()
358+ old .insert (0 , value )
359+ elif kind == Array :
360+ old : Array = old_ycell [key ]
361+ old .clear ()
362+ old .extend (value )
363+ elif kind == Map :
364+ old : Map = old_ycell [key ]
365+ old .clear ()
366+ for k , v in value .items ():
367+ old [k ] = v
368+ else :
369+ old_ycell [key ] = new_cell [key ]
370+
371+ for key in removed_keys :
372+ del old_ycell [key ]
373+
374+ for key in added_keys :
375+ if key in _CELL_KEY_TYPE_MAP :
376+ # we hard-reload cells when keys that require nested types get added
377+ # to allow the frontend to connect observers; this could be changed
378+ # in the future, once frontends learn how to observe all changes
379+ return False
380+ else :
381+ old_ycell [key ] = new_cell [key ]
382+ return True
0 commit comments