Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Traitlet only syncs on 2nd update #786

Open
NateLanza opened this issue Jan 29, 2025 · 0 comments
Open

Traitlet only syncs on 2nd update #786

NateLanza opened this issue Jan 29, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@NateLanza
Copy link

Describe the bug

I've been building a toy extension of Anywidget that will eventually be used in another project. During development, while testing in VSCode, I've noticed that a Dict traitlet I'm using only syncs to the backend on the 2nd and subsequent updates to the traitlet. In other words, the first time the traitlet is updated from the frontend, it does not sync to the backend (despite a call to model.save_changes()) but it does sync on subsequent calls to model.save_changes(). The reference to the dictionary (object on the frontend) is being updated (via structuredClone()).

Even stranger, if the 2nd change doesn't actually change the contents of the dictionary (IE setting a key to the value it already has), the sync will not occur on the 2nd change, even if the 1st change actually altered a value in the dictionary. This persists for repeated meaningless changes; if you continue to set key-value pairs that already exist in the dictionary, no sync will occur even though the first key was substantively changed, so the frontend and backend remain out of sync (again, model.save_changes() is called each time) I'm confused by this behavior, as the way that I've wrapped the Anywidget model always changes the reference to the dictionary, so a new object with one different key-value pair is passed to the traitlet on each call to save_changes().

I understand this could be a traitlet bug; LMK if I should submit it there instead.

Reproduction

My toy widget with the bug can be found at https://github.com/NateLanza/Jupyter-file-storage/tree/f2d81ac63dc42e9953ee627797cd8a4c86e773e8

I've written up a README there which should walk you through the installation and build for that repo; LMK if you have any issues and I'll get back to you ASAP.

I neglected to push my logging up but it's pretty easy: if you look at DataStoreWidget.data_changed(), you can add logging to see whether the traitlet value on the backend changes or not. Once you add logging where you feel like, run the first two cells of test.ipynb. You'll see a widget with two text fields and a set button. The first text field is the key, 2nd is the value. Clicking 'set' syncs to the backend and saves the dictionary in a file. If you do that, then restart your kernel, then try to set the same key to a different value, you'll notice no sync occurs (even though I've set this up to load your old dict in from the file). You can validate that the dict changes in the frontend by logging in data_store.ts. LMK if you have any issues with that too!

Finally, the latest commit on that repo is my workaround fix: on receipt of the model object from the backend, I simply set the dict to {key: 'value'}, run save_changes(), set the dict back to what it came as, then run save_changes() again. This skips the first non-syncing change and gets things flowing. Incredibly, I've had to filter that change out in the data_changed handler on the backend, as it does come through as a first change to the traitlet. If you remove that (lines 50-51 of DataStoreWidget.py) you'll see the first change come through... but only in that scenario. Figured I'd include all that as the workaround may help you isolate the bug

Logs

System Info

System:
    OS: macOS 14.4
    CPU: (10) arm64 Apple M1 Max
    Memory: 1.36 GB / 32.00 GB
    Shell: 5.9 - /bin/zsh
Browsers:
    Chrome: 132.0.6834.111
    Safari: 17.4

anywidget==0.9.13
jupyter_client==8.6.3
jupyter_core==5.7.2
jupyterlab_widgets==3.0.13

Severity

annoyance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant