diff --git a/src/poetry/console/application.py b/src/poetry/console/application.py index 0911e9e07ff..070a8b89b16 100644 --- a/src/poetry/console/application.py +++ b/src/poetry/console/application.py @@ -313,9 +313,10 @@ def _load_plugins(self, io: IO) -> None: self._disable_plugins = io.input.has_parameter_option("--no-plugins") if not self._disable_plugins: + from poetry.plugins.application_plugin import ApplicationPlugin from poetry.plugins.plugin_manager import PluginManager - manager = PluginManager("application.plugin") + manager = PluginManager(ApplicationPlugin.group) manager.load_plugins() manager.activate(self) diff --git a/src/poetry/console/commands/plugin/show.py b/src/poetry/console/commands/plugin/show.py index f772f59ef72..f6c6ad5a46c 100644 --- a/src/poetry/console/commands/plugin/show.py +++ b/src/poetry/console/commands/plugin/show.py @@ -19,6 +19,7 @@ class PluginShowCommand(Command): def handle(self) -> int: from poetry.plugins.application_plugin import ApplicationPlugin + from poetry.plugins.plugin import Plugin from poetry.plugins.plugin_manager import PluginManager from poetry.repositories.installed_repository import InstalledRepository from poetry.utils.env import EnvManager @@ -34,8 +35,8 @@ def handle(self) -> int: ) entry_points = ( - PluginManager("application.plugin").get_plugin_entry_points() - + PluginManager("plugin").get_plugin_entry_points() + PluginManager(ApplicationPlugin.group).get_plugin_entry_points() + + PluginManager(Plugin.group).get_plugin_entry_points() ) system_env = EnvManager.get_system_env(naive=True) diff --git a/src/poetry/factory.py b/src/poetry/factory.py index 2a0b0b6955f..5ff5be0b632 100644 --- a/src/poetry/factory.py +++ b/src/poetry/factory.py @@ -12,6 +12,7 @@ from poetry.locations import CONFIG_DIR from poetry.packages.locker import Locker from poetry.packages.project_package import ProjectPackage +from poetry.plugins.plugin import Plugin from poetry.plugins.plugin_manager import PluginManager from poetry.poetry import Poetry @@ -77,7 +78,7 @@ def create_poetry( poetry, poetry.local_config.get("source", []), config, io ) - plugin_manager = PluginManager("plugin", disable_plugins=disable_plugins) + plugin_manager = PluginManager(Plugin.group, disable_plugins=disable_plugins) plugin_manager.load_plugins() poetry.set_plugin_manager(plugin_manager) plugin_manager.activate(poetry, io) diff --git a/src/poetry/plugins/application_plugin.py b/src/poetry/plugins/application_plugin.py index d7ebc55b416..d1aaf6e1b4f 100644 --- a/src/poetry/plugins/application_plugin.py +++ b/src/poetry/plugins/application_plugin.py @@ -7,14 +7,20 @@ if TYPE_CHECKING: from poetry.console.application import Application + from poetry.console.commands.command import Command class ApplicationPlugin(BasePlugin): """ - Base class for plugins. + Base class for application plugins. """ - type = "application.plugin" + group = "poetry.application.plugin" + + @property + def commands(self) -> list[type[Command]]: + return [] def activate(self, application: Application) -> None: - raise NotImplementedError() + for command in self.commands: + application.command_loader.register_factory(command.name, lambda: command()) diff --git a/src/poetry/plugins/base_plugin.py b/src/poetry/plugins/base_plugin.py index 2366db07964..07146060746 100644 --- a/src/poetry/plugins/base_plugin.py +++ b/src/poetry/plugins/base_plugin.py @@ -1,9 +1,21 @@ from __future__ import annotations +from abc import abstractmethod + class BasePlugin: """ Base class for all plugin types + + The `activate()` method must be implemented and receives the Poetry instance. """ PLUGIN_API_VERSION = "1.0.0" + + @property + @abstractmethod + def group(self) -> str: + """ + Name of entrypoint group the plugin belongs to. + """ + raise NotImplementedError() diff --git a/src/poetry/plugins/plugin.py b/src/poetry/plugins/plugin.py index 38fb149bc07..ea72662c3c2 100644 --- a/src/poetry/plugins/plugin.py +++ b/src/poetry/plugins/plugin.py @@ -1,5 +1,6 @@ from __future__ import annotations +from abc import abstractmethod from typing import TYPE_CHECKING from poetry.plugins.base_plugin import BasePlugin @@ -14,11 +15,10 @@ class Plugin(BasePlugin): """ Generic plugin not related to the console application. - The activate() method must be implemented and receives - the Poetry instance. """ - type = "plugin" + group = "poetry.plugin" + @abstractmethod def activate(self, poetry: Poetry, io: IO) -> None: raise NotImplementedError() diff --git a/src/poetry/plugins/plugin_manager.py b/src/poetry/plugins/plugin_manager.py index 3354b671df0..851d32de6f8 100644 --- a/src/poetry/plugins/plugin_manager.py +++ b/src/poetry/plugins/plugin_manager.py @@ -18,8 +18,8 @@ class PluginManager: This class registers and activates plugins. """ - def __init__(self, type: str, disable_plugins: bool = False) -> None: - self._type = type + def __init__(self, group: str, disable_plugins: bool = False) -> None: + self._group = group self._disable_plugins = disable_plugins self._plugins: list[Plugin] = [] @@ -33,7 +33,7 @@ def load_plugins(self) -> None: self._load_plugin_entrypoint(entrypoint) def get_plugin_entry_points(self) -> list[entrypoints.EntryPoint]: - return entrypoints.get_group_all(f"poetry.{self._type}") + return entrypoints.get_group_all(self._group) def add_plugin(self, plugin: Plugin) -> None: if not isinstance(plugin, (Plugin, ApplicationPlugin)): diff --git a/tests/console/test_application.py b/tests/console/test_application.py index e528f4b6e08..3833d809228 100644 --- a/tests/console/test_application.py +++ b/tests/console/test_application.py @@ -28,8 +28,7 @@ def handle(self) -> int: class AddCommandPlugin(ApplicationPlugin): - def activate(self, application: Application) -> None: - application.command_loader.register_factory("foo", lambda: FooCommand()) + commands = [FooCommand] def test_application_with_plugins(mocker: MockerFixture): diff --git a/tests/plugins/test_plugin_manager.py b/tests/plugins/test_plugin_manager.py index 2f7eb2f56a7..965d04499b5 100644 --- a/tests/plugins/test_plugin_manager.py +++ b/tests/plugins/test_plugin_manager.py @@ -26,7 +26,7 @@ class ManagerFactory(Protocol): - def __call__(self, type: str = "plugin") -> PluginManager: + def __call__(self, group: str = Plugin.group) -> PluginManager: ... @@ -37,9 +37,7 @@ def activate(self, poetry: Poetry, io: BufferedIO) -> None: class MyCommandPlugin(ApplicationPlugin): - @property - def commands(self) -> list[str]: - return [] + commands = [] class InvalidPlugin: @@ -68,15 +66,15 @@ def io() -> BufferedIO: @pytest.fixture() def manager_factory(poetry: Poetry, io: BufferedIO) -> ManagerFactory: - def _manager(type: str = "plugin") -> PluginManager: - return PluginManager(type) + def _manager(group: str = Plugin.group) -> PluginManager: + return PluginManager(group) return _manager @pytest.fixture() def no_plugin_manager(poetry: Poetry, io: BufferedIO) -> PluginManager: - return PluginManager("plugin", disable_plugins=True) + return PluginManager(Plugin.group, disable_plugins=True) def test_load_plugins_and_activate(