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
Bugfix: ensure Checkbox state comparisons are correct by using Qt.CheckState(state) #5541
Bugfix: ensure Checkbox state comparisons are correct by using Qt.CheckState(state) #5541
Conversation
Codecov Report
@@ Coverage Diff @@
## main #5541 +/- ##
==========================================
+ Coverage 89.37% 89.40% +0.02%
==========================================
Files 608 609 +1
Lines 51097 51146 +49
==========================================
+ Hits 45668 45726 +58
+ Misses 5429 5420 -9
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
self.layer.preserve_labels = ( | ||
Qt.CheckState(state) == Qt.CheckState.Checked | ||
) |
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.
Why we use this instead of bool(state)
? There is reason why we need to distinguish partially checked state?
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.
That won't work, the problem is on the right hand side.
Qt.CheckState.Checked is an enum so the comparison still fails.
This can work:
self.layer.contiguous = state == int(Qt.CheckState.Checked)
but I'm not sure I like it, because it seems more likely to break again in the future.
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 no, this self.layer.contiguous = state == int(Qt.CheckState.Checked)
doesn't work:
TypeError: int() argument must be a string, a bytes-like object or a real number
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.
Maybe: self.layer.contiguous = state == Qt.CheckState.Checked.value
would work?
But still I think I prefer the more explicit comparison. 🤷♂️
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 also prefer the more explicit comparison (mostly because I don't need to go look up the enum values to understand the code). But I wouldn't oppose the cast to bool
suggested because Qt's check state is quite well known - wouldn't self.layer.preserve_labels = bool(state)
work?
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.
As we can see changed lines are not covered by tests. Could you add tests to prevent these problems in the future?
BTW, should the various checkboxes appear in the Class attributes? napari/napari/_qt/layer_controls/qt_labels_controls.py Lines 42 to 75 in f47aeed
I think so? But for Labels just contigCheckBox does, not the other 2...
|
yes
One of hole in our review process. |
Add tests for the checkbox states The tests pass on main, Qt5, but fail with main, Qt6
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.
Thanks for following up with further fixes to some of my recent changes @psobolewskiPhD . Looks good to me now, but I'll let @Czaki have the final say.
@@ -63,3 +63,22 @@ def test_changing_colormap_updates_colorbox(qtbot): | |||
color_box.color, | |||
np.round(np.asarray(layer._selected_color) * 255 * layer.opacity), | |||
) | |||
|
|||
|
|||
def test_layercontrols_checkboxes(qtbot): |
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.
Optional: slight preference for splitting this up into multiple tests and refactoring the setup code to be shared and maybe a fixture. But this is also good enough for me right now 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.
Thanks for this comment! With the help of ChatGPT I learned about fixtures and arguments and implemented this. I hope it's correct though 😅
with help of ChatGPT. Tweak all tests per @Czaki to make sure the state propagates. Merge branch 'qt6_checkstate_tests' into bugfix/qt6_checkstate
Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
I've gone over the docstrings one more time. I think this is good to go now? |
Update: I missed a CheckedState and it's kinda a biggie, the layer visibility: #5556 @andy-sweet I think ironically the test checks it correctly because of: napari/napari/_qt/containers/_tests/test_qt_layer_list.py Lines 47 to 54 in ada343a
|
Ah, I remember doing this cast in the tests, but didn't think enough about it. If you remove it, do all the tests pass now? If so, we should remove it to avoid any regressions later. |
@andy-sweet no, I meant the other way: tests pass on Qt6 without this PR, because the test uses the CheckState, but the code currently (before this PR) doesn't (just uses value), so the behavior is bugged on Qt6. This PR fixes the code (and behavior) which makes it better match the test. Edit: Yup, I can confirm: if I change the return of the function used in the test to |
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.
Thanks for the extra catch.
…ckState(state) (#5541) # Description This PR fixes #5540 Basically, the existing Checkbox comparisons fail on Qt6 because we compare the returned `state`, which is 0 or 2, with the enum Qt.CheckState.Checked. This always fails. Now instead of using `state`, I make the comparison with `Qt.CheckState(state)`. See pyside6 docs: https://doc.qt.io/qtforpython/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.CheckState And here's QT5 docs: https://doc.qt.io/qt-5/qt.html#CheckState-enum Note I also found 2 other places in the code where I fixed this, outside of labels layer checkboxes. ## Type of change - [x] Bug-fix (non-breaking change which fixes an issue) # References closes #5540 closes #5556 # How has this been tested? - [x] example: all tests pass with my change --------- Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
…ckState(state) (#5541) # Description This PR fixes #5540 Basically, the existing Checkbox comparisons fail on Qt6 because we compare the returned `state`, which is 0 or 2, with the enum Qt.CheckState.Checked. This always fails. Now instead of using `state`, I make the comparison with `Qt.CheckState(state)`. See pyside6 docs: https://doc.qt.io/qtforpython/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.CheckState And here's QT5 docs: https://doc.qt.io/qt-5/qt.html#CheckState-enum Note I also found 2 other places in the code where I fixed this, outside of labels layer checkboxes. ## Type of change - [x] Bug-fix (non-breaking change which fixes an issue) # References closes #5540 closes #5556 # How has this been tested? - [x] example: all tests pass with my change --------- Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
…ckState(state) (#5541) # Description This PR fixes #5540 Basically, the existing Checkbox comparisons fail on Qt6 because we compare the returned `state`, which is 0 or 2, with the enum Qt.CheckState.Checked. This always fails. Now instead of using `state`, I make the comparison with `Qt.CheckState(state)`. See pyside6 docs: https://doc.qt.io/qtforpython/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.CheckState And here's QT5 docs: https://doc.qt.io/qt-5/qt.html#CheckState-enum Note I also found 2 other places in the code where I fixed this, outside of labels layer checkboxes. ## Type of change - [x] Bug-fix (non-breaking change which fixes an issue) # References closes #5540 closes #5556 # How has this been tested? - [x] example: all tests pass with my change --------- Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
…ckState(state) (#5541) # Description This PR fixes #5540 Basically, the existing Checkbox comparisons fail on Qt6 because we compare the returned `state`, which is 0 or 2, with the enum Qt.CheckState.Checked. This always fails. Now instead of using `state`, I make the comparison with `Qt.CheckState(state)`. See pyside6 docs: https://doc.qt.io/qtforpython/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.CheckState And here's QT5 docs: https://doc.qt.io/qt-5/qt.html#CheckState-enum Note I also found 2 other places in the code where I fixed this, outside of labels layer checkboxes. ## Type of change - [x] Bug-fix (non-breaking change which fixes an issue) # References closes #5540 closes #5556 # How has this been tested? - [x] example: all tests pass with my change --------- Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
…ckState(state) (#5541) # Description This PR fixes #5540 Basically, the existing Checkbox comparisons fail on Qt6 because we compare the returned `state`, which is 0 or 2, with the enum Qt.CheckState.Checked. This always fails. Now instead of using `state`, I make the comparison with `Qt.CheckState(state)`. See pyside6 docs: https://doc.qt.io/qtforpython/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.CheckState And here's QT5 docs: https://doc.qt.io/qt-5/qt.html#CheckState-enum Note I also found 2 other places in the code where I fixed this, outside of labels layer checkboxes. ## Type of change - [x] Bug-fix (non-breaking change which fixes an issue) # References closes #5540 closes #5556 # How has this been tested? - [x] example: all tests pass with my change --------- Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
Description
This PR fixes #5540
Basically, the existing Checkbox comparisons fail on Qt6 because we compare the returned
state
, which is 0 or 2, with the enum Qt.CheckState.Checked. This always fails.Now instead of using
state
, I make the comparison withQt.CheckState(state)
.See pyside6 docs:
https://doc.qt.io/qtforpython/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.CheckState
And here's QT5 docs:
https://doc.qt.io/qt-5/qt.html#CheckState-enum
Note I also found 2 other places in the code where I fixed this, outside of labels layer checkboxes.
Type of change
References
closes #5540
closes #5556
How has this been tested?
as there are small differences between the two Qt bindings.
Final checklist:
trans.
to make them localizable.For more information see our translations guide.