We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Plugin Errors not work in develop 
## 🐛 Bug

<!-- A clear and concise description of what the bug is. -->

$ NAPARI_CATCH_ERRORS=0 python -m napari
16:11:17 ERROR Unhandled exception:
Traceback (most recent call last):
  File "/home/czaki/Dokumenty/projekty/napari/napari/_qt/qt_main_window.py", line 300, in _show_plugin_err_reporter
    plugin_sorter = QtPluginErrReporter(parent=self._qt_window)
  File "/home/czaki/Dokumenty/projekty/napari/napari/_qt/dialogs/qt_plugin_report.py", line 62, in __init__
    from ..plugins import plugin_manager as _pm
ModuleNotFoundError: No module named 'napari._qt.plugins'


## To Reproduce

Steps to reproduce the behavior:

1. install last napari from github
2. try open "Plugin Errors" dialog


<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->

## Expected behavior

<!-- A clear and concise description of what you expected to happen. -->

## Environment

 - Please copy and paste the information at napari info option in help menubar here:

napari: 0.3.7.dev30+gf101ef7
Platform: Linux-4.15.0-112-generic-x86_64-with-debian-buster-sid
Python: 3.7.6 (default, Feb 20 2020, 10:04:45) [GCC 7.4.0]
Qt: 5.14.2
PyQt5: 5.14.2
NumPy: 1.18.5
SciPy: 1.4.1
Dask: 2.17.2
VisPy: 0.6.4

GL version: 4.6.0 NVIDIA 440.100
MAX_TEXTURE_SIZE: 32768

Plugins:
- napari-plugin-engine: 0.1.5
- svg: 0.1.3

 - Any other relevant information:

## Additional context

<!-- Add any other context about the problem here. -->
@sofroniewn @jni 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `napari/_qt/dialogs/qt_plugin_report.py`
Content:
```
1 """Provides a QtPluginErrReporter that allows the user report plugin errors.
2 """
3 from typing import Optional
4 
5 from napari_plugin_engine import PluginManager, standard_metadata
6 from qtpy.QtCore import Qt
7 from qtpy.QtGui import QGuiApplication
8 from qtpy.QtWidgets import (
9     QComboBox,
10     QDialog,
11     QHBoxLayout,
12     QLabel,
13     QPushButton,
14     QTextEdit,
15     QVBoxLayout,
16     QWidget,
17 )
18 
19 from ...plugins.exceptions import format_exceptions
20 
21 
22 class QtPluginErrReporter(QDialog):
23     """Dialog that allows users to review and report PluginError tracebacks.
24 
25     Parameters
26     ----------
27     parent : QWidget, optional
28         Optional parent widget for this widget.
29     initial_plugin : str, optional
30         If provided, errors from ``initial_plugin`` will be shown when the
31         dialog is created, by default None
32 
33     Attributes
34     ----------
35     text_area : qtpy.QtWidgets.QTextEdit
36         The text area where traceback information will be shown.
37     plugin_combo : qtpy.QtWidgets.QComboBox
38         The dropdown menu used to select the current plugin
39     github_button : qtpy.QtWidgets.QPushButton
40         A button that, when pressed, will open an issue at the current plugin's
41         github issue tracker, prepopulated with a formatted traceback.  Button
42         is only visible if a github URL is detected in the package metadata for
43         the current plugin.
44     clipboard_button : qtpy.QtWidgets.QPushButton
45         A button that, when pressed, copies the current traceback information
46         to the clipboard.  (HTML tags are removed in the copied text.)
47     plugin_meta : qtpy.QtWidgets.QLabel
48         A label that will show available plugin metadata (such as home page).
49     """
50 
51     NULL_OPTION = 'select plugin... '
52 
53     def __init__(
54         self,
55         plugin_manager: Optional[PluginManager] = None,
56         *,
57         parent: Optional[QWidget] = None,
58         initial_plugin: Optional[str] = None,
59     ) -> None:
60         super().__init__(parent)
61         if not plugin_manager:
62             from ..plugins import plugin_manager as _pm
63 
64             self.plugin_manager = _pm
65         else:
66             self.plugin_manager = plugin_manager
67 
68         self.setWindowTitle('Recorded Plugin Exceptions')
69         self.setWindowModality(Qt.NonModal)
70         self.layout = QVBoxLayout()
71         self.layout.setSpacing(0)
72         self.layout.setContentsMargins(10, 10, 10, 10)
73         self.setLayout(self.layout)
74 
75         self.text_area = QTextEdit()
76         self.text_area.setTextInteractionFlags(Qt.TextSelectableByMouse)
77         self.text_area.setMinimumWidth(360)
78 
79         # Create plugin dropdown menu
80         self.plugin_combo = QComboBox()
81         self.plugin_combo.addItem(self.NULL_OPTION)
82         bad_plugins = [e.plugin_name for e in self.plugin_manager.get_errors()]
83         self.plugin_combo.addItems(list(sorted(set(bad_plugins))))
84         self.plugin_combo.currentTextChanged.connect(self.set_plugin)
85         self.plugin_combo.setCurrentText(self.NULL_OPTION)
86 
87         # create github button (gets connected in self.set_plugin)
88         self.github_button = QPushButton('Open issue on GitHub', self)
89         self.github_button.setToolTip(
90             "Open a web browser to submit this error log\n"
91             "to the developer's GitHub issue tracker"
92         )
93         self.github_button.hide()
94 
95         # create copy to clipboard button
96         self.clipboard_button = QPushButton()
97         self.clipboard_button.hide()
98         self.clipboard_button.setObjectName("QtCopyToClipboardButton")
99         self.clipboard_button.setToolTip("Copy error log to clipboard")
100         self.clipboard_button.clicked.connect(self.copyToClipboard)
101 
102         # plugin_meta contains a URL to the home page, (and/or other details)
103         self.plugin_meta = QLabel('', parent=self)
104         self.plugin_meta.setObjectName("pluginInfo")
105         self.plugin_meta.setTextFormat(Qt.RichText)
106         self.plugin_meta.setTextInteractionFlags(Qt.TextBrowserInteraction)
107         self.plugin_meta.setOpenExternalLinks(True)
108         self.plugin_meta.setAlignment(Qt.AlignRight)
109 
110         # make layout
111         row_1_layout = QHBoxLayout()
112         row_1_layout.setContentsMargins(11, 5, 10, 0)
113         row_1_layout.addStretch(1)
114         row_1_layout.addWidget(self.plugin_meta)
115         row_2_layout = QHBoxLayout()
116         row_2_layout.setContentsMargins(11, 5, 10, 0)
117         row_2_layout.addWidget(self.plugin_combo)
118         row_2_layout.addStretch(1)
119         row_2_layout.addWidget(self.github_button)
120         row_2_layout.addWidget(self.clipboard_button)
121         row_2_layout.setSpacing(5)
122         self.layout.addLayout(row_1_layout)
123         self.layout.addLayout(row_2_layout)
124         self.layout.addWidget(self.text_area, 1)
125         self.setMinimumWidth(750)
126         self.setMinimumHeight(600)
127 
128         if initial_plugin:
129             self.set_plugin(initial_plugin)
130 
131     def set_plugin(self, plugin: str) -> None:
132         """Set the current plugin shown in the dropdown and text area.
133 
134         Parameters
135         ----------
136         plugin : str
137             name of a plugin that has created an error this session.
138         """
139         self.github_button.hide()
140         self.clipboard_button.hide()
141         try:
142             self.github_button.clicked.disconnect()
143         # when disconnecting a non-existent signal
144         # PySide2 raises runtimeError, PyQt5 raises TypeError
145         except (RuntimeError, TypeError):
146             pass
147 
148         if not plugin or (plugin == self.NULL_OPTION):
149             self.plugin_meta.setText('')
150             self.text_area.setHtml('')
151             return
152 
153         if not self.plugin_manager.get_errors(plugin):
154             raise ValueError(f"No errors reported for plugin '{plugin}'")
155         self.plugin_combo.setCurrentText(plugin)
156 
157         err_string = format_exceptions(plugin, as_html=True)
158         self.text_area.setHtml(err_string)
159         self.clipboard_button.show()
160 
161         # set metadata and outbound links/buttons
162         err0 = self.plugin_manager.get_errors(plugin)[0]
163         meta = standard_metadata(err0.plugin) if err0.plugin else {}
164         meta_text = ''
165         if not meta:
166             self.plugin_meta.setText(meta_text)
167             return
168 
169         url = meta.get('url')
170         if url:
171             meta_text += (
172                 '<span style="color:#999;">plugin home page:&nbsp;&nbsp;'
173                 f'</span><a href="{url}" style="color:#999">{url}</a>'
174             )
175             if 'github.com' in url:
176 
177                 def onclick():
178                     import webbrowser
179 
180                     err = format_exceptions(plugin, as_html=False)
181                     err = (
182                         "<!--Provide detail on the error here-->\n\n\n\n"
183                         "<details>\n<summary>Traceback from napari</summary>"
184                         f"\n\n```\n{err}\n```\n</details>"
185                     )
186                     url = f'{meta.get("url")}/issues/new?&body={err}'
187                     webbrowser.open(url, new=2)
188 
189                 self.github_button.clicked.connect(onclick)
190                 self.github_button.show()
191         self.plugin_meta.setText(meta_text)
192 
193     def copyToClipboard(self) -> None:
194         """Copy current plugin traceback info to clipboard as plain text."""
195         plugin = self.plugin_combo.currentText()
196         err_string = format_exceptions(plugin, as_html=False)
197         cb = QGuiApplication.clipboard()
198         cb.setText(err_string)
199
```

Path: `napari/_qt/dialogs/qt_plugin_table.py`
Content:
```
1 from qtpy.QtCore import Qt
2 from qtpy.QtWidgets import QAbstractItemView, QDialog, QLabel, QVBoxLayout
3 
4 from ..widgets.qt_dict_table import QtDictTable
5 
6 
7 class QtPluginTable(QDialog):
8     def __init__(self, parent, plugin_manager=None):
9         super().__init__(parent)
10         if not plugin_manager:
11             from ..plugins import plugin_manager
12 
13         self.setMaximumHeight(800)
14         self.setMaximumWidth(1280)
15         layout = QVBoxLayout()
16         # maybe someday add a search bar here?
17         title = QLabel("Installed Plugins")
18         title.setObjectName("h2")
19         layout.addWidget(title)
20         # get metadata for successfully registered plugins
21         plugin_manager.discover()
22         data = plugin_manager.list_plugin_metadata()
23         data = list(filter(lambda x: x['plugin_name'] != 'builtins', data))
24         # create a table for it
25         self.table = QtDictTable(
26             parent,
27             data,
28             headers=[
29                 'plugin_name',
30                 'package',
31                 'version',
32                 'url',
33                 'author',
34                 'license',
35             ],
36             min_section_width=60,
37         )
38         self.table.setObjectName("pluginTable")
39         self.table.horizontalHeader().setObjectName("pluginTableHeader")
40         self.table.verticalHeader().setObjectName("pluginTableHeader")
41         self.table.setGridStyle(Qt.NoPen)
42         # prevent editing of table
43         self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
44         layout.addWidget(self.table)
45         self.setLayout(layout)
46         self.setAttribute(Qt.WA_DeleteOnClose)
47
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/napari/_qt/dialogs/qt_plugin_report.py b/napari/_qt/dialogs/qt_plugin_report.py
--- a/napari/_qt/dialogs/qt_plugin_report.py
+++ b/napari/_qt/dialogs/qt_plugin_report.py
@@ -59,7 +59,7 @@
     ) -> None:
         super().__init__(parent)
         if not plugin_manager:
-            from ..plugins import plugin_manager as _pm
+            from ...plugins import plugin_manager as _pm
 
             self.plugin_manager = _pm
         else:
diff --git a/napari/_qt/dialogs/qt_plugin_table.py b/napari/_qt/dialogs/qt_plugin_table.py
--- a/napari/_qt/dialogs/qt_plugin_table.py
+++ b/napari/_qt/dialogs/qt_plugin_table.py
@@ -8,7 +8,7 @@
     def __init__(self, parent, plugin_manager=None):
         super().__init__(parent)
         if not plugin_manager:
-            from ..plugins import plugin_manager
+            from ...plugins import plugin_manager
 
         self.setMaximumHeight(800)
         self.setMaximumWidth(1280)

{"golden_diff": "diff --git a/napari/_qt/dialogs/qt_plugin_report.py b/napari/_qt/dialogs/qt_plugin_report.py\n--- a/napari/_qt/dialogs/qt_plugin_report.py\n+++ b/napari/_qt/dialogs/qt_plugin_report.py\n@@ -59,7 +59,7 @@\n     ) -> None:\n         super().__init__(parent)\n         if not plugin_manager:\n-            from ..plugins import plugin_manager as _pm\n+            from ...plugins import plugin_manager as _pm\n \n             self.plugin_manager = _pm\n         else:\ndiff --git a/napari/_qt/dialogs/qt_plugin_table.py b/napari/_qt/dialogs/qt_plugin_table.py\n--- a/napari/_qt/dialogs/qt_plugin_table.py\n+++ b/napari/_qt/dialogs/qt_plugin_table.py\n@@ -8,7 +8,7 @@\n     def __init__(self, parent, plugin_manager=None):\n         super().__init__(parent)\n         if not plugin_manager:\n-            from ..plugins import plugin_manager\n+            from ...plugins import plugin_manager\n \n         self.setMaximumHeight(800)\n         self.setMaximumWidth(1280)\n", "issue": "Plugin Errors not work in develop \n## \ud83d\udc1b Bug\r\n\r\n<!-- A clear and concise description of what the bug is. -->\r\n\r\n$ NAPARI_CATCH_ERRORS=0 python -m napari\r\n16:11:17 ERROR Unhandled exception:\r\nTraceback (most recent call last):\r\n  File \"/home/czaki/Dokumenty/projekty/napari/napari/_qt/qt_main_window.py\", line 300, in _show_plugin_err_reporter\r\n    plugin_sorter = QtPluginErrReporter(parent=self._qt_window)\r\n  File \"/home/czaki/Dokumenty/projekty/napari/napari/_qt/dialogs/qt_plugin_report.py\", line 62, in __init__\r\n    from ..plugins import plugin_manager as _pm\r\nModuleNotFoundError: No module named 'napari._qt.plugins'\r\n\r\n\r\n## To Reproduce\r\n\r\nSteps to reproduce the behavior:\r\n\r\n1. install last napari from github\r\n2. try open \"Plugin Errors\" dialog\r\n\r\n\r\n<!-- If you have a code sample, error messages, stack traces, please provide it here as well -->\r\n\r\n## Expected behavior\r\n\r\n<!-- A clear and concise description of what you expected to happen. -->\r\n\r\n## Environment\r\n\r\n - Please copy and paste the information at napari info option in help menubar here:\r\n\r\nnapari: 0.3.7.dev30+gf101ef7\r\nPlatform: Linux-4.15.0-112-generic-x86_64-with-debian-buster-sid\r\nPython: 3.7.6 (default, Feb 20 2020, 10:04:45) [GCC 7.4.0]\r\nQt: 5.14.2\r\nPyQt5: 5.14.2\r\nNumPy: 1.18.5\r\nSciPy: 1.4.1\r\nDask: 2.17.2\r\nVisPy: 0.6.4\r\n\r\nGL version: 4.6.0 NVIDIA 440.100\r\nMAX_TEXTURE_SIZE: 32768\r\n\r\nPlugins:\r\n- napari-plugin-engine: 0.1.5\r\n- svg: 0.1.3\r\n\r\n - Any other relevant information:\r\n\r\n## Additional context\r\n\r\n<!-- Add any other context about the problem here. -->\r\n@sofroniewn @jni \n", "before_files": [{"content": "\"\"\"Provides a QtPluginErrReporter that allows the user report plugin errors.\n\"\"\"\nfrom typing import Optional\n\nfrom napari_plugin_engine import PluginManager, standard_metadata\nfrom qtpy.QtCore import Qt\nfrom qtpy.QtGui import QGuiApplication\nfrom qtpy.QtWidgets import (\n    QComboBox,\n    QDialog,\n    QHBoxLayout,\n    QLabel,\n    QPushButton,\n    QTextEdit,\n    QVBoxLayout,\n    QWidget,\n)\n\nfrom ...plugins.exceptions import format_exceptions\n\n\nclass QtPluginErrReporter(QDialog):\n    \"\"\"Dialog that allows users to review and report PluginError tracebacks.\n\n    Parameters\n    ----------\n    parent : QWidget, optional\n        Optional parent widget for this widget.\n    initial_plugin : str, optional\n        If provided, errors from ``initial_plugin`` will be shown when the\n        dialog is created, by default None\n\n    Attributes\n    ----------\n    text_area : qtpy.QtWidgets.QTextEdit\n        The text area where traceback information will be shown.\n    plugin_combo : qtpy.QtWidgets.QComboBox\n        The dropdown menu used to select the current plugin\n    github_button : qtpy.QtWidgets.QPushButton\n        A button that, when pressed, will open an issue at the current plugin's\n        github issue tracker, prepopulated with a formatted traceback.  Button\n        is only visible if a github URL is detected in the package metadata for\n        the current plugin.\n    clipboard_button : qtpy.QtWidgets.QPushButton\n        A button that, when pressed, copies the current traceback information\n        to the clipboard.  (HTML tags are removed in the copied text.)\n    plugin_meta : qtpy.QtWidgets.QLabel\n        A label that will show available plugin metadata (such as home page).\n    \"\"\"\n\n    NULL_OPTION = 'select plugin... '\n\n    def __init__(\n        self,\n        plugin_manager: Optional[PluginManager] = None,\n        *,\n        parent: Optional[QWidget] = None,\n        initial_plugin: Optional[str] = None,\n    ) -> None:\n        super().__init__(parent)\n        if not plugin_manager:\n            from ..plugins import plugin_manager as _pm\n\n            self.plugin_manager = _pm\n        else:\n            self.plugin_manager = plugin_manager\n\n        self.setWindowTitle('Recorded Plugin Exceptions')\n        self.setWindowModality(Qt.NonModal)\n        self.layout = QVBoxLayout()\n        self.layout.setSpacing(0)\n        self.layout.setContentsMargins(10, 10, 10, 10)\n        self.setLayout(self.layout)\n\n        self.text_area = QTextEdit()\n        self.text_area.setTextInteractionFlags(Qt.TextSelectableByMouse)\n        self.text_area.setMinimumWidth(360)\n\n        # Create plugin dropdown menu\n        self.plugin_combo = QComboBox()\n        self.plugin_combo.addItem(self.NULL_OPTION)\n        bad_plugins = [e.plugin_name for e in self.plugin_manager.get_errors()]\n        self.plugin_combo.addItems(list(sorted(set(bad_plugins))))\n        self.plugin_combo.currentTextChanged.connect(self.set_plugin)\n        self.plugin_combo.setCurrentText(self.NULL_OPTION)\n\n        # create github button (gets connected in self.set_plugin)\n        self.github_button = QPushButton('Open issue on GitHub', self)\n        self.github_button.setToolTip(\n            \"Open a web browser to submit this error log\\n\"\n            \"to the developer's GitHub issue tracker\"\n        )\n        self.github_button.hide()\n\n        # create copy to clipboard button\n        self.clipboard_button = QPushButton()\n        self.clipboard_button.hide()\n        self.clipboard_button.setObjectName(\"QtCopyToClipboardButton\")\n        self.clipboard_button.setToolTip(\"Copy error log to clipboard\")\n        self.clipboard_button.clicked.connect(self.copyToClipboard)\n\n        # plugin_meta contains a URL to the home page, (and/or other details)\n        self.plugin_meta = QLabel('', parent=self)\n        self.plugin_meta.setObjectName(\"pluginInfo\")\n        self.plugin_meta.setTextFormat(Qt.RichText)\n        self.plugin_meta.setTextInteractionFlags(Qt.TextBrowserInteraction)\n        self.plugin_meta.setOpenExternalLinks(True)\n        self.plugin_meta.setAlignment(Qt.AlignRight)\n\n        # make layout\n        row_1_layout = QHBoxLayout()\n        row_1_layout.setContentsMargins(11, 5, 10, 0)\n        row_1_layout.addStretch(1)\n        row_1_layout.addWidget(self.plugin_meta)\n        row_2_layout = QHBoxLayout()\n        row_2_layout.setContentsMargins(11, 5, 10, 0)\n        row_2_layout.addWidget(self.plugin_combo)\n        row_2_layout.addStretch(1)\n        row_2_layout.addWidget(self.github_button)\n        row_2_layout.addWidget(self.clipboard_button)\n        row_2_layout.setSpacing(5)\n        self.layout.addLayout(row_1_layout)\n        self.layout.addLayout(row_2_layout)\n        self.layout.addWidget(self.text_area, 1)\n        self.setMinimumWidth(750)\n        self.setMinimumHeight(600)\n\n        if initial_plugin:\n            self.set_plugin(initial_plugin)\n\n    def set_plugin(self, plugin: str) -> None:\n        \"\"\"Set the current plugin shown in the dropdown and text area.\n\n        Parameters\n        ----------\n        plugin : str\n            name of a plugin that has created an error this session.\n        \"\"\"\n        self.github_button.hide()\n        self.clipboard_button.hide()\n        try:\n            self.github_button.clicked.disconnect()\n        # when disconnecting a non-existent signal\n        # PySide2 raises runtimeError, PyQt5 raises TypeError\n        except (RuntimeError, TypeError):\n            pass\n\n        if not plugin or (plugin == self.NULL_OPTION):\n            self.plugin_meta.setText('')\n            self.text_area.setHtml('')\n            return\n\n        if not self.plugin_manager.get_errors(plugin):\n            raise ValueError(f\"No errors reported for plugin '{plugin}'\")\n        self.plugin_combo.setCurrentText(plugin)\n\n        err_string = format_exceptions(plugin, as_html=True)\n        self.text_area.setHtml(err_string)\n        self.clipboard_button.show()\n\n        # set metadata and outbound links/buttons\n        err0 = self.plugin_manager.get_errors(plugin)[0]\n        meta = standard_metadata(err0.plugin) if err0.plugin else {}\n        meta_text = ''\n        if not meta:\n            self.plugin_meta.setText(meta_text)\n            return\n\n        url = meta.get('url')\n        if url:\n            meta_text += (\n                '<span style=\"color:#999;\">plugin home page:&nbsp;&nbsp;'\n                f'</span><a href=\"{url}\" style=\"color:#999\">{url}</a>'\n            )\n            if 'github.com' in url:\n\n                def onclick():\n                    import webbrowser\n\n                    err = format_exceptions(plugin, as_html=False)\n                    err = (\n                        \"<!--Provide detail on the error here-->\\n\\n\\n\\n\"\n                        \"<details>\\n<summary>Traceback from napari</summary>\"\n                        f\"\\n\\n```\\n{err}\\n```\\n</details>\"\n                    )\n                    url = f'{meta.get(\"url\")}/issues/new?&body={err}'\n                    webbrowser.open(url, new=2)\n\n                self.github_button.clicked.connect(onclick)\n                self.github_button.show()\n        self.plugin_meta.setText(meta_text)\n\n    def copyToClipboard(self) -> None:\n        \"\"\"Copy current plugin traceback info to clipboard as plain text.\"\"\"\n        plugin = self.plugin_combo.currentText()\n        err_string = format_exceptions(plugin, as_html=False)\n        cb = QGuiApplication.clipboard()\n        cb.setText(err_string)\n", "path": "napari/_qt/dialogs/qt_plugin_report.py"}, {"content": "from qtpy.QtCore import Qt\nfrom qtpy.QtWidgets import QAbstractItemView, QDialog, QLabel, QVBoxLayout\n\nfrom ..widgets.qt_dict_table import QtDictTable\n\n\nclass QtPluginTable(QDialog):\n    def __init__(self, parent, plugin_manager=None):\n        super().__init__(parent)\n        if not plugin_manager:\n            from ..plugins import plugin_manager\n\n        self.setMaximumHeight(800)\n        self.setMaximumWidth(1280)\n        layout = QVBoxLayout()\n        # maybe someday add a search bar here?\n        title = QLabel(\"Installed Plugins\")\n        title.setObjectName(\"h2\")\n        layout.addWidget(title)\n        # get metadata for successfully registered plugins\n        plugin_manager.discover()\n        data = plugin_manager.list_plugin_metadata()\n        data = list(filter(lambda x: x['plugin_name'] != 'builtins', data))\n        # create a table for it\n        self.table = QtDictTable(\n            parent,\n            data,\n            headers=[\n                'plugin_name',\n                'package',\n                'version',\n                'url',\n                'author',\n                'license',\n            ],\n            min_section_width=60,\n        )\n        self.table.setObjectName(\"pluginTable\")\n        self.table.horizontalHeader().setObjectName(\"pluginTableHeader\")\n        self.table.verticalHeader().setObjectName(\"pluginTableHeader\")\n        self.table.setGridStyle(Qt.NoPen)\n        # prevent editing of table\n        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)\n        layout.addWidget(self.table)\n        self.setLayout(layout)\n        self.setAttribute(Qt.WA_DeleteOnClose)\n", "path": "napari/_qt/dialogs/qt_plugin_table.py"}], "after_files": [{"content": "\"\"\"Provides a QtPluginErrReporter that allows the user report plugin errors.\n\"\"\"\nfrom typing import Optional\n\nfrom napari_plugin_engine import PluginManager, standard_metadata\nfrom qtpy.QtCore import Qt\nfrom qtpy.QtGui import QGuiApplication\nfrom qtpy.QtWidgets import (\n    QComboBox,\n    QDialog,\n    QHBoxLayout,\n    QLabel,\n    QPushButton,\n    QTextEdit,\n    QVBoxLayout,\n    QWidget,\n)\n\nfrom ...plugins.exceptions import format_exceptions\n\n\nclass QtPluginErrReporter(QDialog):\n    \"\"\"Dialog that allows users to review and report PluginError tracebacks.\n\n    Parameters\n    ----------\n    parent : QWidget, optional\n        Optional parent widget for this widget.\n    initial_plugin : str, optional\n        If provided, errors from ``initial_plugin`` will be shown when the\n        dialog is created, by default None\n\n    Attributes\n    ----------\n    text_area : qtpy.QtWidgets.QTextEdit\n        The text area where traceback information will be shown.\n    plugin_combo : qtpy.QtWidgets.QComboBox\n        The dropdown menu used to select the current plugin\n    github_button : qtpy.QtWidgets.QPushButton\n        A button that, when pressed, will open an issue at the current plugin's\n        github issue tracker, prepopulated with a formatted traceback.  Button\n        is only visible if a github URL is detected in the package metadata for\n        the current plugin.\n    clipboard_button : qtpy.QtWidgets.QPushButton\n        A button that, when pressed, copies the current traceback information\n        to the clipboard.  (HTML tags are removed in the copied text.)\n    plugin_meta : qtpy.QtWidgets.QLabel\n        A label that will show available plugin metadata (such as home page).\n    \"\"\"\n\n    NULL_OPTION = 'select plugin... '\n\n    def __init__(\n        self,\n        plugin_manager: Optional[PluginManager] = None,\n        *,\n        parent: Optional[QWidget] = None,\n        initial_plugin: Optional[str] = None,\n    ) -> None:\n        super().__init__(parent)\n        if not plugin_manager:\n            from ...plugins import plugin_manager as _pm\n\n            self.plugin_manager = _pm\n        else:\n            self.plugin_manager = plugin_manager\n\n        self.setWindowTitle('Recorded Plugin Exceptions')\n        self.setWindowModality(Qt.NonModal)\n        self.layout = QVBoxLayout()\n        self.layout.setSpacing(0)\n        self.layout.setContentsMargins(10, 10, 10, 10)\n        self.setLayout(self.layout)\n\n        self.text_area = QTextEdit()\n        self.text_area.setTextInteractionFlags(Qt.TextSelectableByMouse)\n        self.text_area.setMinimumWidth(360)\n\n        # Create plugin dropdown menu\n        self.plugin_combo = QComboBox()\n        self.plugin_combo.addItem(self.NULL_OPTION)\n        bad_plugins = [e.plugin_name for e in self.plugin_manager.get_errors()]\n        self.plugin_combo.addItems(list(sorted(set(bad_plugins))))\n        self.plugin_combo.currentTextChanged.connect(self.set_plugin)\n        self.plugin_combo.setCurrentText(self.NULL_OPTION)\n\n        # create github button (gets connected in self.set_plugin)\n        self.github_button = QPushButton('Open issue on GitHub', self)\n        self.github_button.setToolTip(\n            \"Open a web browser to submit this error log\\n\"\n            \"to the developer's GitHub issue tracker\"\n        )\n        self.github_button.hide()\n\n        # create copy to clipboard button\n        self.clipboard_button = QPushButton()\n        self.clipboard_button.hide()\n        self.clipboard_button.setObjectName(\"QtCopyToClipboardButton\")\n        self.clipboard_button.setToolTip(\"Copy error log to clipboard\")\n        self.clipboard_button.clicked.connect(self.copyToClipboard)\n\n        # plugin_meta contains a URL to the home page, (and/or other details)\n        self.plugin_meta = QLabel('', parent=self)\n        self.plugin_meta.setObjectName(\"pluginInfo\")\n        self.plugin_meta.setTextFormat(Qt.RichText)\n        self.plugin_meta.setTextInteractionFlags(Qt.TextBrowserInteraction)\n        self.plugin_meta.setOpenExternalLinks(True)\n        self.plugin_meta.setAlignment(Qt.AlignRight)\n\n        # make layout\n        row_1_layout = QHBoxLayout()\n        row_1_layout.setContentsMargins(11, 5, 10, 0)\n        row_1_layout.addStretch(1)\n        row_1_layout.addWidget(self.plugin_meta)\n        row_2_layout = QHBoxLayout()\n        row_2_layout.setContentsMargins(11, 5, 10, 0)\n        row_2_layout.addWidget(self.plugin_combo)\n        row_2_layout.addStretch(1)\n        row_2_layout.addWidget(self.github_button)\n        row_2_layout.addWidget(self.clipboard_button)\n        row_2_layout.setSpacing(5)\n        self.layout.addLayout(row_1_layout)\n        self.layout.addLayout(row_2_layout)\n        self.layout.addWidget(self.text_area, 1)\n        self.setMinimumWidth(750)\n        self.setMinimumHeight(600)\n\n        if initial_plugin:\n            self.set_plugin(initial_plugin)\n\n    def set_plugin(self, plugin: str) -> None:\n        \"\"\"Set the current plugin shown in the dropdown and text area.\n\n        Parameters\n        ----------\n        plugin : str\n            name of a plugin that has created an error this session.\n        \"\"\"\n        self.github_button.hide()\n        self.clipboard_button.hide()\n        try:\n            self.github_button.clicked.disconnect()\n        # when disconnecting a non-existent signal\n        # PySide2 raises runtimeError, PyQt5 raises TypeError\n        except (RuntimeError, TypeError):\n            pass\n\n        if not plugin or (plugin == self.NULL_OPTION):\n            self.plugin_meta.setText('')\n            self.text_area.setHtml('')\n            return\n\n        if not self.plugin_manager.get_errors(plugin):\n            raise ValueError(f\"No errors reported for plugin '{plugin}'\")\n        self.plugin_combo.setCurrentText(plugin)\n\n        err_string = format_exceptions(plugin, as_html=True)\n        self.text_area.setHtml(err_string)\n        self.clipboard_button.show()\n\n        # set metadata and outbound links/buttons\n        err0 = self.plugin_manager.get_errors(plugin)[0]\n        meta = standard_metadata(err0.plugin) if err0.plugin else {}\n        meta_text = ''\n        if not meta:\n            self.plugin_meta.setText(meta_text)\n            return\n\n        url = meta.get('url')\n        if url:\n            meta_text += (\n                '<span style=\"color:#999;\">plugin home page:&nbsp;&nbsp;'\n                f'</span><a href=\"{url}\" style=\"color:#999\">{url}</a>'\n            )\n            if 'github.com' in url:\n\n                def onclick():\n                    import webbrowser\n\n                    err = format_exceptions(plugin, as_html=False)\n                    err = (\n                        \"<!--Provide detail on the error here-->\\n\\n\\n\\n\"\n                        \"<details>\\n<summary>Traceback from napari</summary>\"\n                        f\"\\n\\n```\\n{err}\\n```\\n</details>\"\n                    )\n                    url = f'{meta.get(\"url\")}/issues/new?&body={err}'\n                    webbrowser.open(url, new=2)\n\n                self.github_button.clicked.connect(onclick)\n                self.github_button.show()\n        self.plugin_meta.setText(meta_text)\n\n    def copyToClipboard(self) -> None:\n        \"\"\"Copy current plugin traceback info to clipboard as plain text.\"\"\"\n        plugin = self.plugin_combo.currentText()\n        err_string = format_exceptions(plugin, as_html=False)\n        cb = QGuiApplication.clipboard()\n        cb.setText(err_string)\n", "path": "napari/_qt/dialogs/qt_plugin_report.py"}, {"content": "from qtpy.QtCore import Qt\nfrom qtpy.QtWidgets import QAbstractItemView, QDialog, QLabel, QVBoxLayout\n\nfrom ..widgets.qt_dict_table import QtDictTable\n\n\nclass QtPluginTable(QDialog):\n    def __init__(self, parent, plugin_manager=None):\n        super().__init__(parent)\n        if not plugin_manager:\n            from ...plugins import plugin_manager\n\n        self.setMaximumHeight(800)\n        self.setMaximumWidth(1280)\n        layout = QVBoxLayout()\n        # maybe someday add a search bar here?\n        title = QLabel(\"Installed Plugins\")\n        title.setObjectName(\"h2\")\n        layout.addWidget(title)\n        # get metadata for successfully registered plugins\n        plugin_manager.discover()\n        data = plugin_manager.list_plugin_metadata()\n        data = list(filter(lambda x: x['plugin_name'] != 'builtins', data))\n        # create a table for it\n        self.table = QtDictTable(\n            parent,\n            data,\n            headers=[\n                'plugin_name',\n                'package',\n                'version',\n                'url',\n                'author',\n                'license',\n            ],\n            min_section_width=60,\n        )\n        self.table.setObjectName(\"pluginTable\")\n        self.table.horizontalHeader().setObjectName(\"pluginTableHeader\")\n        self.table.verticalHeader().setObjectName(\"pluginTableHeader\")\n        self.table.setGridStyle(Qt.NoPen)\n        # prevent editing of table\n        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)\n        layout.addWidget(self.table)\n        self.setLayout(layout)\n        self.setAttribute(Qt.WA_DeleteOnClose)\n", "path": "napari/_qt/dialogs/qt_plugin_table.py"}]}