Repository: napari/napari

Issue:
napari cli: enable --with option for npe2 widgets 
## Description

Right now trying to launch an  npe2 dock widget from the cli fails. For example:

```sh
napari --with napari-animation
```

(with napari-animation installed as an npe2 plugin)

gives

```
Traceback (most recent call last):
  File "/Users/nclack/opt/miniforge3/envs/dev-napari-npe2-console/bin/napari", line 33, in <module>
    sys.exit(load_entry_point('napari', 'console_scripts', 'napari')())
  File "/Users/nclack/src/CZI/napari/napari/__main__.py", line 449, in main
    _run()
  File "/Users/nclack/src/CZI/napari/napari/__main__.py", line 327, in _run
    viewer.window.add_plugin_dock_widget(pname)
  File "/Users/nclack/src/CZI/napari/napari/_qt/qt_main_window.py", line 655, in add_plugin_dock_widget
    widget_name = list(plugin_manager._dock_widgets[plugin_name])[0]
KeyError: 'napari-animation'
```

## References

I ran into this while looking into this comment from @jni.  This issue focuses on the idea of pre-loading a plugin widget using the `--with` option, but doesn't address the `napari path/to/file.npy`.  See discussion below for more.

> Can we update this to be a single command that "executes" the plugin? e.g. `napari path/to/file.npy`? That's not a super 
> interesting example, but I always have to look up the equivalent command for pre-loading a plugin widget.

_Originally posted by @jni in https://github.com/napari/napari/pull/3769#discussion_r767255994_


Discussion:

Resolving patch:
diff --git a/napari/__main__.py b/napari/__main__.py
--- a/napari/__main__.py
+++ b/napari/__main__.py
@@ -12,6 +12,8 @@
 from textwrap import wrap
 from typing import Any, Dict, List
 
+import napari.plugins._npe2 as _npe2
+
 
 class InfoAction(argparse.Action):
     def __call__(self, *args, **kwargs):
@@ -290,9 +292,13 @@ def _run():
             pname, *wnames = args.with_
             if wnames:
                 for wname in wnames:
-                    plugin_manager.get_widget(pname, wname)
+                    _npe2.get_widget_contribution(
+                        pname, wname
+                    ) or plugin_manager.get_widget(pname, wname)
             else:
-                plugin_manager.get_widget(pname)
+                _npe2.get_widget_contribution(
+                    pname
+                ) or plugin_manager.get_widget(pname)
 
         from napari._qt.widgets.qt_splash_screen import NapariSplashScreen
 
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
@@ -658,9 +658,13 @@ def add_plugin_dock_widget(
         """
         from ..plugins import _npe2
 
-        Widget = _npe2.get_widget_contribution(plugin_name, widget_name)
+        Widget = None
         dock_kwargs = {}
 
+        result = _npe2.get_widget_contribution(plugin_name, widget_name)
+        if result:
+            Widget, widget_name = result
+
         if Widget is None:
             Widget, dock_kwargs = plugin_manager.get_widget(
                 plugin_name, widget_name
diff --git a/napari/plugins/_npe2.py b/napari/plugins/_npe2.py
--- a/napari/plugins/_npe2.py
+++ b/napari/plugins/_npe2.py
@@ -108,14 +108,13 @@ def write_layers(
 
 @npe2_or_return_none
 def get_widget_contribution(
-    plugin_name: str, widget_name: str
-) -> Optional[WidgetCallable]:
+    plugin_name: str, widget_name: Optional[str] = None
+) -> Optional[Tuple[WidgetCallable, str]]:
     for contrib in npe2.PluginManager.instance().iter_widgets():
-        if (
-            contrib.plugin_name == plugin_name
-            and contrib.display_name == widget_name
+        if contrib.plugin_name == plugin_name and (
+            not widget_name or contrib.display_name == widget_name
         ):
-            return contrib.get_callable()
+            return contrib.get_callable(), contrib.display_name
     return None
 
 


Test patch: