wolfhece.plugins.manager ======================== .. py:module:: wolfhece.plugins.manager .. autoapi-nested-parse:: Companion plugin manager. Manages discovery, loading, enabling and disabling of external companion plugins, and integrates them into the viewer menu bar. Quick usage ----------- :: from wolfhece.plugins.manager import PluginManagerCompanion mgr = PluginManagerCompanion() mgr.proxy.attach(viewer) mgr.build() # adds "Plugins" top-level menu mgr.discover() # scans default directory and activates enabled plugins # Programmatic enable/disable: mgr.plugin_manager.disable('dot_picker') mgr.plugin_manager.enable('dot_picker') # Inventory for docs / notebooks / diagnostics: rows = mgr.plugin_manager.list_available(refresh=True) # each row has: name, display_name, loaded, enabled, active, activable, reason Persistence ----------- Enabled/disabled state is stored in the viewer's :class:`~wolfhece.PyConfig.WolfConfiguration` under the ``PLUGINS_DISABLED`` key (list of disabled plugin names). The plugins directory is stored under ``PLUGINS_DIRECTORY`` (empty string → built-in ``wolfhece/data/plugins``). Module Contents --------------- .. py:data:: _logger .. py:class:: PluginManager(viewer: wolfhece.PyDraw.WolfMapViewer) Manages the runtime lifecycle of companion plugins for one viewer. .. attribute:: plugins All discovered plugins (loaded or failed). :type: list[PluginInfo] .. attribute:: active Mapping of plugin name → the currently active companion instance. :type: dict[str, AbstractUICompanion] .. py:attribute:: _viewer .. py:attribute:: plugins :type: list[wolfhece.plugins.loader.PluginInfo] :value: [] .. py:attribute:: active :type: dict[str, wolfhece.plugins.abc.AbstractUICompanion] .. py:method:: discover(directory: pathlib.Path | str | None = None) -> list[wolfhece.plugins.loader.PluginInfo] Scan *directory*, load plugins, and apply the stored enable/disable state. :param directory: Override the plugins directory. ``None`` reads the value from the viewer configuration (falling back to the built-in ``wolfhece/data/plugins``). :return: The refreshed :attr:`plugins` list. .. py:method:: list_available(*, refresh: bool = True, directory: pathlib.Path | str | None = None) -> list[dict[str, object]] Return a normalized inventory of discovered plugins. This is the preferred routine to know which plugin names are currently activable from the registry. :param refresh: When ``True`` (default), perform discovery first. :param directory: Optional discovery override, forwarded to :meth:`discover`. :return: List of rows with these keys: ``name``, ``display_name``, ``loaded``, ``enabled``, ``active``, ``activable``, ``reason``, ``load_error``. .. py:method:: enable(name: str) -> bool Enable the plugin *name* and activate it if not already running. :return: ``True`` on success, ``False`` if the plugin was not found or could not be loaded. .. py:method:: disable(name: str) -> bool Disable the plugin *name* and destroy its active companion. :return: ``True`` on success, ``False`` if the plugin was not found. .. py:method:: is_enabled(name: str) -> bool Return whether the plugin *name* is currently enabled. .. py:method:: sync_enabled_state() -> None Read the persisted disabled list and apply changes to live plugins. Called after the global options dialog has been closed so that any enable/disable changes made there take effect immediately in the running viewer, without requiring a restart. .. py:method:: _activate(info: wolfhece.plugins.loader.PluginInfo) -> None Instantiate, wire up menu, and store the companion. .. py:method:: _find(name: str) -> wolfhece.plugins.loader.PluginInfo | None .. py:method:: _get_config() Return the viewer's WolfConfiguration, or ``None`` if unavailable. .. py:method:: _configured_directory() -> pathlib.Path | None Read the plugins directory from the viewer config. .. py:method:: _disabled_names() -> list[str] .. py:method:: _save_state() -> None .. py:class:: PluginManagerCompanion Bases: :py:obj:`wolfhece.plugins.abc.AbstractUICompanion` .. autoapi-inheritance-diagram:: wolfhece.plugins.manager.PluginManagerCompanion :parts: 1 :private-bases: Companion that manages external companion plugins. Adds a *Plugins* top-level menu to the viewer with items to discover, reload, and toggle individual plugins. Typical integration in a viewer subclass or startup script:: from wolfhece.plugins.manager import PluginManagerCompanion mgr = PluginManagerCompanion() mgr.proxy.attach(viewer) mgr.build() # installs the "Plugins" menu mgr.discover() # scans directory and activates enabled plugins .. py:attribute:: _plugin_manager :type: PluginManager | None :value: None .. py:property:: plugin_manager :type: PluginManager Underlying plugin lifecycle manager (created lazily after attach). .. py:method:: start() -> None No-op — the manager operates through the menu, not interactively. .. py:method:: menu_host() -> str Keep the manager menu as a top-level entry in the menubar. .. py:method:: menu_spec() Declare the companion's menu as a ``(title, items)`` pair. Override this to add a menu without writing wx code:: def menu_spec(self) -> tuple[str, list[MenuEntry]] | None: return (_('My Tool'), [ MenuItem(_('Run'), self._on_run, _('Execute the tool')), SEPARATOR, SubMenuSpec(_('Settings'), [ MenuItem(_('Configure…'), self._on_configure), ]), ]) Return ``None`` (the default) when no top-level menu is needed. Called automatically by :meth:`build`. Do not call directly. .. py:method:: discover(directory: pathlib.Path | str | None = None) -> list[wolfhece.plugins.loader.PluginInfo] Scan *directory*, activate plugins, then refresh the menu. :param directory: Override the plugins directory. ``None`` reads from the viewer configuration. :return: The refreshed list of :class:`~wolfhece._plugin_loader.PluginInfo`. .. py:method:: list_available_plugins(*, refresh: bool = True, directory: pathlib.Path | str | None = None) -> list[dict[str, object]] Return plugin inventory rows from the underlying registry. Convenience wrapper used by notebooks/scripts that access the viewer's already-instantiated plugin registry. .. py:method:: _menu_items() -> list .. py:method:: _make_toggle(name: str) Return a menu-event handler that toggles plugin *name*. .. py:method:: _on_discover(_ctx) -> None .. py:method:: _on_choose_dir(_ctx) -> None .. py:method:: _persist_directory(path: pathlib.Path) -> None .. py:method:: _rebuild_menu() -> None