Repository: napari/napari

Issue:
`Viewer.window.add_dock_widget` does not support list of `FunctionGui` from `magicgui`
## 🐛 Bug

The `Viewer.window.add_dock_widget` expects a `Sequence` of `QWigets` or a single `FunctionGui`, it does not support a `Sequence` of `FunctionGui`, this possibly a bug from the changes of `magicgui v0.2`.

The programmer can circumvent this issue by sending the `FunctionGui.native` objects, but I'm not sure if this is the expected behavior.

## To Reproduce

Execute this code:

```python3
import napari
from magicgui import magicgui

viewer = napari.Viewer()

@magicgui(call_button='hi')
def _first_widget() -> None:
    print('hi')

@magicgui(call_button='bye')
def _second_widget() -> None:
    print('bye')

viewer.window.add_dock_widget([_first_widget, _second_widget])                                                                                                                                            
napari.run()
```

Outputting:
```python3
Traceback (most recent call last):
  File "error.py", line 14, in <module>
    viewer.window.add_dock_widget([_first_widget, _second_widget])
  File "/home/jordao/Softwares/napari/napari/_qt/qt_main_window.py", line 994, in add_dock_widget
    dock_widget = QtViewerDockWidget(
  File "/home/jordao/Softwares/napari/napari/_qt/widgets/qt_viewer_dock_widget.py", line 131, in __init__
    widget = combine_widgets(widget, vertical=is_vertical)
  File "/home/jordao/Softwares/napari/napari/_qt/utils.py", line 245, in combine_widgets
    raise TypeError(
TypeError: "widget" must be a QWidget or a sequence of QWidgets
```

It works if I change to:

```python3
import napari
from magicgui import magicgui

viewer = napari.Viewer()

@magicgui(call_button='hi')
def _first_widget() -> None:
    print('hi')

@magicgui(call_button='bye')
def _second_widget() -> None:
    print('bye')

viewer.window.add_dock_widget([_first_widget.native, _second_widget.native])                                                                                                                                            
napari.run()
```

## Environment

```
napari: 0.4.7
Platform: Linux-5.8.0-50-generic-x86_64-with-glibc2.10
System: Ubuntu 20.04.2 LTS
Python: 3.8.8 (default, Apr 13 2021, 19:58:26) [GCC 7.3.0]
Qt: 5.15.2
PyQt5: 5.15.4
NumPy: 1.20.3
SciPy: 1.6.3
Dask: 2021.05.0
VisPy: 0.6.6

OpenGL:
- GL version: 4.6 (Compatibility Profile) Mesa 20.2.6
- MAX_TEXTURE_SIZE: 16384

Screens:
- screen 1: resolution 3440x1440, scale 1.0

Plugins:
- console: 0.0.3
- napari-dexp: 0.1.dev2+g1c663ea.d20210517
- napari-ibacktracker: 0.1.dev1+gf589318.d20210517
- napari-segm-annotation: 0.1.dev1+g7fbf135.d20210518
- svg: 0.1.5
```



Discussion:

Resolving patch:
diff --git a/napari/_qt/utils.py b/napari/_qt/utils.py
--- a/napari/_qt/utils.py
+++ b/napari/_qt/utils.py
@@ -235,16 +235,21 @@ def combine_widgets(
         return widgets.native  # type: ignore
     elif isinstance(widgets, QWidget):
         return widgets
-    elif is_sequence(widgets) and all(isinstance(i, QWidget) for i in widgets):
-        container = QWidget()
-        container.setLayout(QVBoxLayout() if vertical else QHBoxLayout())
-        for widget in widgets:
-            container.layout().addWidget(widget)
-        return container
-    else:
-        raise TypeError(
-            trans._('"widget" must be a QWidget or a sequence of QWidgets')
-        )
+    elif is_sequence(widgets):
+        # the same as above, compatibility with magicgui v0.2.0
+        widgets = [
+            i.native if isinstance(getattr(i, 'native', None), QWidget) else i
+            for i in widgets
+        ]
+        if all(isinstance(i, QWidget) for i in widgets):
+            container = QWidget()
+            container.setLayout(QVBoxLayout() if vertical else QHBoxLayout())
+            for widget in widgets:
+                container.layout().addWidget(widget)
+            return container
+    raise TypeError(
+        trans._('"widget" must be a QWidget or a sequence of QWidgets')
+    )
 
 
 def delete_qapp(app):


Test patch: