Repository: napari/napari

Issue:
Points-data6-3 Test bug
## 🐛 Bug
Well... I was wrong about @ttung  PR #957  fixing the recently broken test.
specifically, the `Points-data6-3` in `layer_test_data` is throwing problems,  I thought it was PyQt5-specific, but it doesn't seem to be

see: https://cirrus-ci.com/task/6267251569459200?command=test#L122
<details>
<summary>Full stack trace</summary>

```
________________________ test_add_layer[Points-data6-3] ________________________
viewermodel_factory = <function viewermodel_factory.<locals>.actual_factory at 0x7f5ed4739ea0>
layer_class = <class 'napari.layers.points.points.Points'>
data = array([[11.52405671,  0.6935089 ,  9.6275892 ],
       [10.73905532,  9.55078023,  1.26010958],
       [ 7.37847017, 1...3457305,  4.33625033],
       [14.55827554, 16.21624613, 19.25676998],
       [11.84174046,  9.10982733,  2.61232675]])
ndim = 3
    @pytest.mark.parametrize('layer_class, data, ndim', layer_test_data)
    def test_add_layer(viewermodel_factory, layer_class, data, ndim):
        view, viewer = viewermodel_factory(ndisplay=ndim)
        add_layer_by_type(viewer, layer_class, data)
>       check_viewer_functioning(viewer, view, data, ndim)
napari/_qt/_tests/test_qt_viewer.py:31: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
napari/_tests/utils.py:114: in check_viewer_functioning
    viewer.dims.ndisplay = 2
napari/components/dims.py:296: in ndisplay
    self.events.ndisplay()
napari/utils/event.py:508: in __call__
    self._invoke_callback(cb, event)
napari/utils/event.py:529: in _invoke_callback
    cb_event=(cb, event),
napari/utils/event.py:523: in _invoke_callback
    cb(event)
napari/components/viewer_model.py:400: in _update_layers
    layer.dims.ndisplay = self.dims.ndisplay
napari/components/dims.py:296: in ndisplay
    self.events.ndisplay()
napari/utils/event.py:508: in __call__
    self._invoke_callback(cb, event)
napari/utils/event.py:529: in _invoke_callback
    cb_event=(cb, event),
napari/utils/event.py:523: in _invoke_callback
    cb(event)
napari/layers/base/base.py:383: in _update_dims
    self.refresh()
napari/layers/base/base.py:601: in refresh
    self.events.set_data()
napari/utils/event.py:508: in __call__
    self._invoke_callback(cb, event)
napari/utils/event.py:529: in _invoke_callback
    cb_event=(cb, event),
napari/utils/event.py:523: in _invoke_callback
    cb(event)
napari/_vispy/vispy_points_layer.py:51: in _on_data_change
    self._on_highlight_change()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <napari._vispy.vispy_points_layer.VispyPointsLayer object at 0x7f5ece27bef0>
event = None
    def _on_highlight_change(self, event=None):
        if len(self.layer._highlight_index) > 0:
            # Color the hovered or selected points
>           data = self.layer._data_view[self.layer._highlight_index]
E           IndexError: index 6 is out of bounds for axis 0 with size 1
napari/_vispy/vispy_points_layer.py:86: IndexError
```

</details>

i'll try to look at it soon, but if anyone that has particular knowledge of the points layer wants to take a look, that would be great


Discussion:

Resolving patch:
diff --git a/conftest.py b/conftest.py
--- a/conftest.py
+++ b/conftest.py
@@ -1,5 +1,3 @@
 # pytest ignores these
 collect_ignore = ['setup.py', 'napari_gui']
-pytest_plugins = [
-    'napari._tests.infra.viewer',
-]
+pytest_plugins = ['napari._tests.infra.viewer']
diff --git a/napari/layers/points/points.py b/napari/layers/points/points.py
--- a/napari/layers/points/points.py
+++ b/napari/layers/points/points.py
@@ -1019,6 +1019,7 @@ def selected_data(self, selected_data):
 
         # Update properties based on selected points
         if len(self._selected_data) == 0:
+            self._set_highlight()
             return
         index = self._selected_data
         edge_colors = np.unique(self.edge_color[index], axis=0)
@@ -1047,6 +1048,7 @@ def selected_data(self, selected_data):
         n_unique_properties = np.array([len(v) for v in properties.values()])
         if np.all(n_unique_properties == 1):
             self.current_properties = properties
+        self._set_highlight()
 
     def interaction_box(self, index):
         """Create the interaction box around a list of points in view.
@@ -1243,7 +1245,8 @@ def _set_view_slice(self):
                 ind = list(self._indices_view).index(c)
                 selected.append(ind)
         self._selected_view = selected
-        self._set_highlight()
+        with self.events.highlight.blocker():
+            self._set_highlight(force=True)
 
     def _set_highlight(self, force=False):
         """Render highlights of shapes including boundaries, vertices,
@@ -1272,7 +1275,10 @@ def _set_highlight(self, force=False):
                 if len(self._selected_view) > 0:
                     index = copy(self._selected_view)
                     # highlight the hovered point if not in adding mode
-                    if self._value is not None and self._mode != Mode.ADD:
+                    if (
+                        self._value in self._indices_view
+                        and self._mode == Mode.SELECT
+                    ):
                         hover_point = list(self._indices_view).index(
                             self._value
                         )
@@ -1282,8 +1288,11 @@ def _set_highlight(self, force=False):
                             index.append(hover_point)
                     index.sort()
                 else:
-                    # don't highlight hovered points in add mode
-                    if self._mode != Mode.ADD:
+                    # only highlight hovered points in select mode
+                    if (
+                        self._value in self._indices_view
+                        and self._mode == Mode.SELECT
+                    ):
                         hover_point = list(self._indices_view).index(
                             self._value
                         )
@@ -1509,6 +1518,8 @@ def on_mouse_move(self, event):
                     self._set_highlight()
             else:
                 self._set_highlight()
+        else:
+            self._set_highlight()
 
     def on_mouse_press(self, event):
         """Called whenever mouse pressed in canvas.


Test patch: