Repository: napari/napari

Issue:
Consider dropping support for plugin discovery by naming convention
I just spent some time trying to figure out why one of my examples in magicgui (`napari_forward_refs`) was getting "magically" run every time I ran one of the other napari examples.  Turns out the reason was that, by default, we consider any module starting with the word "napari" to be a potential plugin, and because python considers the current directory to be in PYTHONPATH, that means that if you import napari in one thing, they _all_ get imported.  I could of course just rename all those things, but in many "examples" cases, you don't want to rename them!  So, I propose that we _require_ plugins to announce themselves using `entry_points`, rather than just blindly importing and searching every module in PYTHONPATH that starts with "`napari_`"


Discussion:
I'm 100% +1 on this. As you know I dislike naming convention as a way to signal things. 

Resolving patch:
diff --git a/napari/_qt/qt_main_window.py b/napari/_qt/qt_main_window.py
--- a/napari/_qt/qt_main_window.py
+++ b/napari/_qt/qt_main_window.py
@@ -428,6 +428,9 @@ def _add_plugins_menu(self):
             'Add Dock Widget', self._qt_window
         )
 
+        if not plugins.dock_widgets:
+            plugins.discover_dock_widgets()
+
         # Get names of all plugins providing dock widgets or functions
         plugin_widgets = chain(plugins.dock_widgets, plugins.function_widgets)
         plugin_counts = Counter(plug_name for plug_name, _ in plugin_widgets)
diff --git a/napari/plugins/__init__.py b/napari/plugins/__init__.py
--- a/napari/plugins/__init__.py
+++ b/napari/plugins/__init__.py
@@ -31,9 +31,7 @@
 
 
 # the main plugin manager instance for the `napari` plugin namespace.
-plugin_manager = PluginManager(
-    'napari', discover_entry_point='napari.plugin', discover_prefix='napari_'
-)
+plugin_manager = PluginManager('napari', discover_entry_point='napari.plugin')
 with plugin_manager.discovery_blocked():
     plugin_manager.add_hookspecs(hook_specifications)
     plugin_manager.register(_builtins, name='builtins')
@@ -93,7 +91,7 @@ def register_dock_widget(
         dock_widgets[key] = (_cls, kwargs)
 
 
-magicgui_sig = {
+_magicgui_sig = {
     name
     for name, p in signature(magicgui).parameters.items()
     if p.kind is p.KEYWORD_ONLY
@@ -141,7 +139,7 @@ def register_function_widget(
             )
             continue
 
-        valid_magic_kwargs = set(signature(func).parameters) | magicgui_sig
+        valid_magic_kwargs = set(signature(func).parameters) | _magicgui_sig
         extra_kwargs = set(magic_kwargs) - valid_magic_kwargs
         if extra_kwargs:
             warn(
@@ -175,14 +173,15 @@ def register_function_widget(
         function_widgets[key] = (func, magic_kwargs, dock_kwargs)
 
 
-plugin_manager.hook.napari_experimental_provide_dock_widget.call_historic(
-    result_callback=register_dock_widget, with_impl=True
-)
-
+def discover_dock_widgets():
+    """Trigger discovery of dock_widgets plugins"""
+    dw_hook = plugin_manager.hook.napari_experimental_provide_dock_widget
+    dw_hook.call_historic(result_callback=register_dock_widget, with_impl=True)
+    fw_hook = plugin_manager.hook.napari_experimental_provide_function_widget
+    fw_hook.call_historic(
+        result_callback=register_function_widget, with_impl=True
+    )
 
-plugin_manager.hook.napari_experimental_provide_function_widget.call_historic(
-    result_callback=register_function_widget, with_impl=True
-)
 
 #: Template to use for namespacing a plugin item in the menu bar
 menu_item_template = '{}: {}'


Test patch: