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

Handle buffers in Widget._should_send_property #1595

Merged
merged 9 commits into from
Aug 9, 2017

Conversation

vidartf
Copy link
Member

@vidartf vidartf commented Aug 6, 2017

Previous check in _should_send_property() did not handle buffers. After this change, the comparison is performed in the serialized state which also prevents creation of new widgets/instances during comparison.

Fixes #1592.

Previous test did not handle buffers.. After this change, the comparison
is performed in the serialized state which also prevents creation of new
widgets/instances during comparison.
Ensure that Widget.set_state sends the expected update messages
Also, fix the case when the state is serialized with keys in a different order, by parsing the json we generated with jsondumps.
Also add copyright, change tests to use nose assert for better error messages.
…ay, or python 3 bytes.

We disregard the python 2 buffer type - it is obsolete, even on python 2.

See jupyter-widgets#1194
@jasongrout
Copy link
Member

jasongrout commented Aug 9, 2017

@maartenbreddels - the last commit (7d56205) changes the definition of what is a binary object in python for the custom serializers - basically it adds bytearray and gets rid of the python 2 buffer (which is superseded by memoryview, even on python 2).

What do you think?

@jasongrout
Copy link
Member

@vidartf - what do you think of my changes? I feel like this is ready to merge now, so if you and @maartenbreddels approve it, let's merge.

@maartenbreddels
Copy link
Member

LGTM 👍

split_value = _remove_buffers({ key: to_json(value, self)})
split_lock = _remove_buffers({ key: self._property_lock[key]})
# Compare state and buffer_paths
if (jsonloads(jsondumps(split_value[0])) == jsonloads(jsondumps(split_lock[0]))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather pass sort_keys=True to dumps rather than pass it back through loads, but it is not critical and I have not profiled the two.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I also factored out this comparison into a top-level function.

@@ -483,7 +483,7 @@ def _compare(self, a, b):
else:
return a == b

def _compare_buffers(self, a, b, key):
def _buffer_list_equal(self, a, b):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have this as an extension point, keeping the key could be very informative as to which kind of comparison to perform. If anything, it's a problem with the current _compare that it does not have it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E.g. for certain keys you might want to do a floating point comparison with a given precision, while for another you need exact equality. Without the key, you will not be able to determine which comparison to apply.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on this being an extension point? I don't understand how you're thinking of this as an extension point.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean extension point as in "something an inheriting class might want to override".

Copy link
Member

@jasongrout jasongrout Aug 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this comparison depends on the top-level put/remove buffer function implementations, so I factored out the comparison to also be a top-level function.

Copy link
Member

@jasongrout jasongrout Aug 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean extension point as in "something an inheriting class might want to override".

Ah. Since it depends on the implementation of the top-level functions (i.e., what exactly can be in the buffers list), I think it makes more sense to not override it, and instead put it at the top level too.

Copy link
Member Author

@vidartf vidartf Aug 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation works for me, but if someone uses a serializer/deserialize set that might introduce noise when data is passed through a loop (a != serializer(deserialize(a))), e.g. floating point inaccuracies, they will want to override this comparison.

It is still possible to do that by overriding the _should_send_property function, but it will be more brittle as it needs to take into account the internals of that method (e.g. _property_lock).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I might be over-engineering this one. Other fields in the state other than buffers might also have this issue, so there is no obvious reason to give buffers preferential treatment.

@vidartf
Copy link
Member Author

vidartf commented Aug 9, 2017

Went through it, and only found some minor points commented above. Neither are sticking points for me, so feel free to make the final decision on them as you see fit and merge.

Compare deterministic json strings instead of rehydrating them into objects.
@jasongrout
Copy link
Member

jasongrout commented Aug 9, 2017

One more iteration to try to avoid copying if possible (in python 3, or python 2 with byte memoryviews). @maartenbreddels, @vidartf - does 0f0761c look good to you?

Edit: actually, 0f0761c

@jasongrout
Copy link
Member

@vidartf said on gitter:

@jasongrout Does memoryview.tobytes() actually copy the buffer? I think your changes are ok either way, but just FMI

@jasongrout jasongrout merged commit ee00a61 into jupyter-widgets:master Aug 9, 2017
@vidartf vidartf deleted the fix-should-send branch August 9, 2017 20:59
@github-actions github-actions bot added the resolved-locked Closed issues are locked after 30 days inactivity. Please open a new issue for related discussion. label Feb 11, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
resolved-locked Closed issues are locked after 30 days inactivity. Please open a new issue for related discussion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Receiving binary buffers from frontend fails
3 participants