Example #1
0
def mock_pm(sample_plugin):
    mock_reg = MagicMock()
    with patch.object(PluginManager, 'discover'):
        _pm = PluginManager(reg=mock_reg)
    _pm.register(sample_plugin)
    with patch('npe2.PluginManager.instance', return_value=_pm):
        yield _pm
Example #2
0
def mock_npe2_pm():
    """Mock plugin manager with no registered plugins."""
    mock_reg = MagicMock()
    with patch.object(PluginManager, 'discover'):
        _pm = PluginManager(reg=mock_reg)
    with patch('npe2.PluginManager.instance', return_value=_pm):
        yield _pm
Example #3
0
def _initialize_plugins():
    _npe2pm = _PluginManager.instance()

    settings = get_settings()
    if settings.schema_version >= '0.4.0':
        for p in settings.plugins.disabled_plugins:
            _npe2pm.disable(p)

    _npe2pm.discover(include_npe1=settings.plugins.use_npe2_adaptor)
    _npe2pm.events.enablement_changed.connect(
        _npe2._on_plugin_enablement_change)

    # this is a workaround for the fact that briefcase does not seem to include
    # napari's entry_points.txt in the bundled app, so the builtin plugins
    # don't get detected.  So we just register it manually.  This could
    # potentially be removed when we move to a different bundle strategy
    if 'napari' not in _npe2pm._manifests:
        mf_file = Path(__file__).parent.parent / 'builtins.yaml'
        mf = PluginManifest.from_file(mf_file)
        mf.package_metadata = PackageMetadata.for_package('napari')
        _npe2pm.register(mf)

    # Disable plugins listed as disabled in settings, or detected in npe2
    _from_npe2 = {m.name for m in _npe2pm.iter_manifests()}
    if 'napari' in _from_npe2:
        _from_npe2.update({'napari', 'builtins'})
    plugin_manager._skip_packages = _from_npe2
    plugin_manager._blocked.update(settings.plugins.disabled_plugins)

    if settings.plugins.use_npe2_adaptor:
        # prevent npe1 plugin_manager discovery
        # (this doesn't prevent manual registration)
        plugin_manager.discover = lambda *a, **k: None
    else:
        plugin_manager._initialize()
Example #4
0
    def _on_enabled_checkbox(self, state: int):
        """Called with `state` when checkbox is clicked."""
        enabled = bool(state)
        plugin_name = self.plugin_name.text()
        pm2 = PluginManager.instance()
        if plugin_name in pm2:
            pm2.enable(plugin_name) if state else pm2.disable(plugin_name)
            return

        for npe1_name, _, distname in plugin_manager.iter_available():
            if distname and (distname == plugin_name):
                plugin_manager.set_blocked(npe1_name, not enabled)
Example #5
0
def test_write(mock_pm: PluginManager):
    # saving an image without a writer goes straight to npe2.write
    # it will use our plugin writer
    image = Image(np.random.rand(20, 20), name='ex_img')
    _npe2.write_layers('some_file.tif', [image])
    mock_pm.commands.get.assert_called_once_with(f'{PLUGIN_NAME}.my_writer')

    # points won't trigger our sample writer
    mock_pm.commands.get.reset_mock()
    points = Points(np.random.rand(20, 2), name='ex_points')
    _npe2.write_layers('some_file.tif', [points])
    mock_pm.commands.get.assert_not_called()

    # calling _npe2.write_layers with a specific writer contribution should
    # directly execute the writer.exec with arguments appropriate for the
    # writer spec (single or multi-writer)
    mock_pm.commands.get.reset_mock()
    writer = mock_pm.get_manifest(PLUGIN_NAME).contributions.writers[0]
    writer = MagicMock(wraps=writer)
    writer.exec.return_value = ['']
    assert _npe2.write_layers('some_file.tif', [points], writer=writer) == ['']
    mock_pm.commands.get.assert_not_called()
    writer.exec.assert_called_once()
    assert writer.exec.call_args_list[0].kwargs['args'][0] == 'some_file.tif'
Example #6
0
    def refresh(self):
        if self.refresh_state != RefreshState.DONE:
            self.refresh_state = RefreshState.OUTDATED
            return
        self.refresh_state = RefreshState.REFRESHING
        self.installed_list.clear()
        self.available_list.clear()

        # fetch installed
        from npe2 import PluginManager

        from ...plugins import plugin_manager

        plugin_manager.discover()  # since they might not be loaded yet

        self.already_installed = set()

        def _add_to_installed(distname, enabled, npe_version=1):
            norm_name = normalized_name(distname or '')
            if distname:
                try:
                    meta = metadata(distname)
                except PackageNotFoundError:
                    self.refresh_state = RefreshState.OUTDATED
                    return  # a race condition has occurred and the package is uninstalled by another thread
                if len(meta) == 0:
                    # will not add builtins.
                    return
                self.already_installed.add(norm_name)
            else:
                meta = {}

            self.installed_list.addItem(
                PackageMetadata(
                    metadata_version="1.0",
                    name=norm_name,
                    version=meta.get('version', ''),
                    summary=meta.get('summary', ''),
                    home_page=meta.get('url', ''),
                    author=meta.get('author', ''),
                    license=meta.get('license', ''),
                ),
                installed=True,
                enabled=enabled,
                npe_version=npe_version,
            )

        pm2 = PluginManager.instance()
        for manifest in pm2.iter_manifests():
            distname = normalized_name(manifest.name or '')
            if distname in self.already_installed or distname == 'napari':
                continue
            enabled = not pm2.is_disabled(manifest.name)
            _add_to_installed(distname, enabled, npe_version=2)

        for (
                plugin_name,
                _mod_name,
                distname,
        ) in plugin_manager.iter_available():
            # not showing these in the plugin dialog
            if plugin_name in ('napari_plugin_engine', ):
                continue
            if distname in self.already_installed:
                continue
            _add_to_installed(distname,
                              not plugin_manager.is_blocked(plugin_name))

        self.installed_label.setText(
            trans._(
                "Installed Plugins ({amount})",
                amount=len(self.already_installed),
            ))

        # fetch available plugins
        settings = get_settings()
        use_hub = (running_as_bundled_app() or running_as_constructor_app()
                   or settings.plugins.plugin_api.name == "napari_hub")
        if use_hub:
            conda_forge = running_as_constructor_app()
            self.worker = create_worker(iter_hub_plugin_info,
                                        conda_forge=conda_forge)
        else:
            self.worker = create_worker(iter_napari_plugin_info)

        self.worker.yielded.connect(self._handle_yield)
        self.worker.finished.connect(self.working_indicator.hide)
        self.worker.finished.connect(self._update_count_in_label)
        self.worker.finished.connect(self._end_refresh)
        self.worker.start()
Example #7
0
def sys_info(as_html=False):
    """Gathers relevant module versions for troubleshooting purposes.

    Parameters
    ----------
    as_html : bool
        if True, info will be returned as HTML, suitable for a QTextEdit widget
    """
    from npe2 import PluginManager as Npe2PluginManager

    from napari.plugins import plugin_manager

    sys_version = sys.version.replace('\n', ' ')
    text = (f"<b>napari</b>: {napari.__version__}<br>"
            f"<b>Platform</b>: {platform.platform()}<br>")

    __sys_name = _sys_name()
    if __sys_name:
        text += f"<b>System</b>: {__sys_name}<br>"

    text += f"<b>Python</b>: {sys_version}<br>"

    try:
        from qtpy import API_NAME, PYQT_VERSION, PYSIDE_VERSION, QtCore

        if API_NAME == 'PySide2':
            API_VERSION = PYSIDE_VERSION
        elif API_NAME == 'PyQt5':
            API_VERSION = PYQT_VERSION
        else:
            API_VERSION = ''

        text += (f"<b>Qt</b>: {QtCore.__version__}<br>"
                 f"<b>{API_NAME}</b>: {API_VERSION}<br>")

    except Exception as e:
        text += f"<b>Qt</b>: Import failed ({e})<br>"

    modules = (
        ('numpy', 'NumPy'),
        ('scipy', 'SciPy'),
        ('dask', 'Dask'),
        ('vispy', 'VisPy'),
    )

    loaded = {}
    for module, name in modules:
        try:
            loaded[module] = __import__(module)
            text += f"<b>{name}</b>: {loaded[module].__version__}<br>"
        except Exception as e:
            text += f"<b>{name}</b>: Import failed ({e})<br>"

    text += "<br><b>OpenGL:</b><br>"

    if loaded.get('vispy', False):
        sys_info_text = ("<br>".join([
            loaded['vispy'].sys_info().split("\n")[index]
            for index in [-4, -3]
        ]).replace("'", "").replace("<br>", "<br>  - "))
        text += f'  - {sys_info_text}<br>'
    else:
        text += "  - failed to load vispy"

    text += "<br><b>Screens:</b><br>"

    try:
        from qtpy.QtGui import QGuiApplication

        screen_list = QGuiApplication.screens()
        for i, screen in enumerate(screen_list, start=1):
            text += f"  - screen {i}: resolution {screen.geometry().width()}x{screen.geometry().height()}, scale {screen.devicePixelRatio()}<br>"
    except Exception as e:
        text += f"  - failed to load screen information {e}"

    plugin_manager.discover()
    plugin_strings = {}
    for meta in plugin_manager.list_plugin_metadata():
        plugin_name = meta.get('plugin_name')
        if plugin_name == 'builtins':
            continue
        version = meta.get('version')
        version_string = f": {version}" if version else ""
        plugin_strings[plugin_name] = f"  - {plugin_name}{version_string}"

    npe2_plugin_manager = Npe2PluginManager.instance()
    for manifest in npe2_plugin_manager.iter_manifests():
        plugin_name = manifest.name
        if plugin_name in ("napari", "builtins"):
            continue
        version = manifest.package_version
        version_string = f": {version}" if version else ""
        plugin_strings[plugin_name] = f"  - {plugin_name}{version_string}"

    text += '<br><b>Plugins</b>:'
    text += (("<br>" + "<br>".join(sorted(plugin_strings.values())))
             if plugin_strings else '  None')

    if not as_html:
        text = (text.replace("<br>", "\n").replace("<b>",
                                                   "").replace("</b>", ""))
    return text
Example #8
0
from npe2 import PluginManager as _PluginManager

from ..settings import get_settings
from ._plugin_manager import NapariPluginManager

__all__ = ["plugin_manager", "menu_item_template"]

_npe2pm = _PluginManager.instance()

# the main plugin manager instance for the `napari` plugin namespace.
plugin_manager = NapariPluginManager()
plugin_manager._initialize()

# Disable plugins listed as disabled in settings, or detected in npe2
_from_npe2 = {m.package_metadata.name for m in _npe2pm._manifests.values()}
_toblock = get_settings().plugins.disabled_plugins.union(_from_npe2)
plugin_manager._blocked.update(_toblock)

#: Template to use for namespacing a plugin item in the menu bar
menu_item_template = '{}: {}'