diff --git a/sopel/plugins/handlers.py b/sopel/plugins/handlers.py index 9216b7a53..eee1c056d 100644 --- a/sopel/plugins/handlers.py +++ b/sopel/plugins/handlers.py @@ -48,6 +48,7 @@ import importlib.util import inspect import itertools +import logging import os import sys from typing import Optional, TYPE_CHECKING, TypedDict @@ -61,6 +62,9 @@ from types import ModuleType +LOGGER = logging.getLogger(__name__) + + class PluginMetaDescription(TypedDict): """Meta description of a plugin, as a dictionary. @@ -620,14 +624,20 @@ def get_version(self) -> Optional[str]: if ( version is None - and hasattr(self.module, "__package__") - and self.module.__package__ is not None + and hasattr(self.entry_point, "dist") + and hasattr(self.entry_point.dist, "name") ): + dist_name = self.entry_point.dist.name try: - version = importlib.metadata.version(self.module.__package__) - except ValueError: - # package name is probably empty-string; just give up - pass + version = importlib.metadata.version(dist_name) + except (ValueError, importlib.metadata.PackageNotFoundError): + LOGGER.warning("Cannot determine version of %r", dist_name) + except Exception: + LOGGER.warning( + "Unexpected error occurred while checking the version of %r", + dist_name, + exc_info=True, + ) return version diff --git a/test/plugins/test_plugins_handlers.py b/test/plugins/test_plugins_handlers.py index 15546d14d..67a2d6034 100644 --- a/test/plugins/test_plugins_handlers.py +++ b/test/plugins/test_plugins_handlers.py @@ -142,3 +142,21 @@ def test_folder_plugin_imports(plugin_folder): handler = handlers.PyFilePlugin(plugin_folder) handler.load() assert handler.module.foo == 'bar baz' + + +def test_get_version_entrypoint_package_does_not_match(plugin_tmpfile): + # See gh-2593, wherein an entrypoint plugin whose project/package names + # are not equal raised an exception that propagated too far + distrib_dir = os.path.dirname(plugin_tmpfile.strpath) + sys.path.append(distrib_dir) + + try: + entry_point = importlib.metadata.EntryPoint( + 'test_plugin', 'file_mod', 'sopel.plugins') + plugin = handlers.EntryPointPlugin(entry_point) + plugin.load() + plugin.module.__package__ = "FAKEFAKEFAKE" + # Under gh-2593, this call raises a PackageNotFound error + assert plugin.get_version() is None + finally: + sys.path.remove(distrib_dir)