Repository: holoviz/holoviews

Issue:
New and Unexpected Warning: Tool of type could not be found and could not be activated by default.
#### ALL software version info
MacOS Ventura 13.2
holoviews 1.15.4 pyhd8ed1ab_0 conda-forge
jupyter 1.0.0  py310h2ec42d9_8 conda-forge

#### Description of expected behavior and the observed behavior
Trying to specify `default_tools` in Scatter plot `opts`.  Expect no warning.  In response to the following Scatter plot of a 99K x 8 matrix of doubles:
```
(hv.Scatter(Xpca.loc[~Xpca.node.isin(['n0','n1','n57917'])], 
             kdims='x', vdims=['y','node','id','labels','date','in_deg','out_deg','tot_edge'])
            .opts(default_tools=['hover','save','box_zoom','reset'],
                  height=800, width=900, color='tot_edge', xlabel='PC1',ylabel='PC2',
                  colorbar=True, clim=(0,10), cmap='jet',show_grid=True
                 )
 )
```
Get the following warning:
```
WARNING:param.OverlayPlot09107: Tool of type 'pan' could not be found and could not be activated by default.
WARNING:param.OverlayPlot09107: Tool of type 'wheel_zoom' could not be found and could not be activated by default.
```

#### Complete, minimal, self-contained example code that reproduces the issue
Data:

x	y	node	labels	date	id	in_deg	out_deg	tot_edge
6.28234	-3.198913	n2	:TRANSACTION	2017-01-02	100276789	1	0	1
6.071874	-3.812788	n3	:TRANSACTION	2017-01-02	100276792	1	0	1
5.716742	3.669202	n4	:TRANSACTION	2017-01-02	100276813	2	0	2
5.612813	-0.583601	n5	:TRANSACTION	2017-01-02	100276814	2	0	2
5.656079	-0.364387	n6	:TRANSACTION	2017-01-02	100276822	2	0	2

Code:
```
(hv.Scatter(data, kdims='x', vdims=['y','node','id','labels','date','in_deg','out_deg','tot_edge'])
          .opts(default_tools=['hover','save','box_zoom','reset'],
                height=800, width=900, color='tot_edge', xlabel='PC1',ylabel='PC2',
                colorbar=True, clim=(0,10), cmap='jet',show_grid=True
               )
)
```

#### Stack traceback and/or browser JavaScript console output

#### Screenshots or screencasts of the bug in action



Discussion:
This is reproducible by the following and is related to the change made in https://github.com/holoviz/holoviews/pull/5480:

``` python
import holoviews as hv
hv.extension("bokeh")
hv.Scatter([]).opts(default_tools=[])
```

Resolving patch:
diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py
--- a/holoviews/plotting/bokeh/element.py
+++ b/holoviews/plotting/bokeh/element.py
@@ -68,11 +68,12 @@
 
 class ElementPlot(BokehPlot, GenericElementPlot):
 
-    active_tools = param.List(default=['pan', 'wheel_zoom'], doc="""
+    active_tools = param.List(default=None, doc="""
         Allows specifying which tools are active by default. Note
         that only one tool per gesture type can be active, e.g.
         both 'pan' and 'box_zoom' are drag tools, so if both are
-        listed only the last one will be active.""")
+        listed only the last one will be active. As a default 'pan'
+        and 'wheel_zoom' will be used if the tools are enabled.""")
 
     align = param.ObjectSelector(default='start', objects=['start', 'center', 'end'], doc="""
         Alignment (vertical or horizontal) of the plot in a layout.""")
@@ -569,15 +570,23 @@ def _set_active_tools(self, plot):
         "Activates the list of active tools"
         if plot is None:
             return
-        for tool in self.active_tools:
+
+        if self.active_tools is None:
+            enabled_tools = set(self.default_tools + self.tools)
+            active_tools =  {'pan', 'wheel_zoom'} & enabled_tools
+        else:
+            active_tools = self.active_tools
+
+        for tool in active_tools:
             if isinstance(tool, str):
-                tool_type = TOOL_TYPES[tool]
+                tool_type = TOOL_TYPES.get(tool, type(None))
                 matching = [t for t in plot.toolbar.tools
                             if isinstance(t, tool_type)]
                 if not matching:
-                    self.param.warning('Tool of type %r could not be found '
-                                       'and could not be activated by default.'
-                                       % tool)
+                    self.param.warning(
+                        f'Tool of type {tool!r} could not be found '
+                        'and could not be activated by default.'
+                    )
                     continue
                 tool = matching[0]
             if isinstance(tool, tools.Drag):


Test patch:
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -74,7 +74,7 @@ jobs:
         run: |
           conda activate test-environment
           conda uninstall panel bokeh --force -y --offline || echo "packages already removed"
-          pip install "git+https://github.com/holoviz/panel.git@branch-1.0"
+          pip install "git+https://github.com/holoviz/panel.git"
       - name: doit test_unit
         run: |
           conda activate test-environment
diff --git a/holoviews/tests/core/test_dynamic.py b/holoviews/tests/core/test_dynamic.py
--- a/holoviews/tests/core/test_dynamic.py
+++ b/holoviews/tests/core/test_dynamic.py
@@ -990,7 +990,7 @@ def callback(x): return Curve([1,2,3])
         dmap.periodic(0.01, 100, param_fn=lambda i: {'x':i})
         self.assertEqual(xval.x, 100)
 
-    @pytest.mark.flaky
+    @pytest.mark.flaky(max_runs=3)
     def test_periodic_param_fn_non_blocking(self):
         def callback(x): return Curve([1,2,3])
         xval = Stream.define('x',x=0)()
diff --git a/holoviews/tests/plotting/bokeh/test_callbacks.py b/holoviews/tests/plotting/bokeh/test_callbacks.py
--- a/holoviews/tests/plotting/bokeh/test_callbacks.py
+++ b/holoviews/tests/plotting/bokeh/test_callbacks.py
@@ -287,7 +287,7 @@ def test_box_edit_callback_initialized_server(self):
         plot = bokeh_server_renderer.get_plot(boxes)
         assert 'data' in plot.handles['cds']._callbacks
 
-    @pytest.mark.flaky
+    @pytest.mark.flaky(max_runs=3)
     def test_poly_edit_callback(self):
         polys = Polygons([[(0, 0), (2, 2), (4, 0)]])
         poly_edit = PolyEdit(source=polys)
diff --git a/holoviews/tests/plotting/bokeh/test_server.py b/holoviews/tests/plotting/bokeh/test_server.py
--- a/holoviews/tests/plotting/bokeh/test_server.py
+++ b/holoviews/tests/plotting/bokeh/test_server.py
@@ -1,6 +1,7 @@
 import time
 
 import param
+import pytest
 
 from holoviews.core.spaces import DynamicMap
 from holoviews.core.options import Store
@@ -123,6 +124,7 @@ def test_launch_server_with_stream(self):
         self.assertEqual(cb.streams, [stream])
         assert 'rangesupdate' in plot.state._event_callbacks
 
+    @pytest.mark.flaky(max_runs=3)
     def test_launch_server_with_complex_plot(self):
         dmap = DynamicMap(lambda x_range, y_range: Curve([]), streams=[RangeXY()])
         overlay = dmap * HLine(0)