-
Notifications
You must be signed in to change notification settings - Fork 949
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
Conversation
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
f830665
to
40cd07c
Compare
be6df90
to
349f556
Compare
Also, fix the case when the state is serialized with keys in a different order, by parsing the json we generated with jsondumps.
0dbb6b7
to
db04817
Compare
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
@maartenbreddels - the last commit (7d56205) changes the definition of what is a binary object in python for the custom serializers - basically it adds What do you think? |
@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. |
LGTM 👍 |
ipywidgets/widgets/widget.py
Outdated
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])) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
ipywidgets/widgets/widget.py
Outdated
@@ -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): |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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".
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
).
There was a problem hiding this comment.
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.
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.
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 |
1c4d8a6
to
0f0761c
Compare
@vidartf said on gitter:
|
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.