Skip to content

Commit

Permalink
Add a plugin show command
Browse files Browse the repository at this point in the history
  • Loading branch information
sdispater committed Mar 8, 2021
1 parent b8a93ce commit a690ce7
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 2 deletions.
1 change: 1 addition & 0 deletions poetry/console/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def _load() -> Type[Command]:
"env use",
# Plugin commands
"plugin add",
"plugin show",
# Self commands
"self update",
]
Expand Down
95 changes: 95 additions & 0 deletions poetry/console/commands/plugin/show.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from collections import defaultdict
from typing import TYPE_CHECKING
from typing import DefaultDict
from typing import Dict
from typing import List
from typing import Union

from poetry.console.commands.command import Command


if TYPE_CHECKING:
from poetry.core.packages.package import Package


class PluginShowCommand(Command):

name = "plugin show"

description = "Shows information about the currently installed plugins."

def handle(self) -> int:
from poetry.plugins.application_plugin import ApplicationPlugin
from poetry.plugins.plugin_manager import PluginManager
from poetry.repositories.installed_repository import InstalledRepository
from poetry.utils.env import EnvManager
from poetry.utils.helpers import canonicalize_name

plugins: DefaultDict[str, Dict[str, Union["Package", List[str]]]] = defaultdict(
lambda: {
"package": None,
"plugins": [],
"application_plugins": [],
}
)

entry_points = (
PluginManager("application.plugin").get_plugin_entry_points()
+ PluginManager("plugin").get_plugin_entry_points()
)

system_env = EnvManager.get_system_env()
installed_repository = InstalledRepository.load(
system_env, with_dependencies=True
)

packages_by_name = {pkg.name: pkg for pkg in installed_repository.packages}

for entry_point in entry_points:
plugin = entry_point.load()
category = "plugins"
if issubclass(plugin, ApplicationPlugin):
category = "application_plugins"

package = packages_by_name[canonicalize_name(entry_point.name)]
plugins[package.pretty_name]["package"] = package
plugins[package.pretty_name][category].append(entry_point)

for name, info in plugins.items():
package = info["package"]
self.line("")
self.line(
" • <c1>{}</c1> (<c2>{}</c2>){}".format(
name,
package.version,
" " + package.description if package.description else "",
)
)
provide_line = " "
if info["plugins"]:
provide_line += " <info>{}</info> plugin{}".format(
len(info["plugins"]), "s" if len(info["plugins"]) > 1 else ""
)

if info["application_plugins"]:
if info["plugins"]:
provide_line += " and"

provide_line += " <info>{}</info> application plugin{}".format(
len(info["application_plugins"]),
"s" if len(info["application_plugins"]) > 1 else "",
)

self.line(provide_line)

if package.requires:
self.line("")
self.line(" <info>Dependencies</info>")
for dependency in package.requires:
self.line(
" - {} (<c2>{}</c2>)".format(
dependency.pretty_name, dependency.pretty_constraint
)
)

return 0
2 changes: 1 addition & 1 deletion poetry/console/commands/show.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def handle(self) -> Optional[int]:
]

table.add_rows(rows)
table.render(self.io)
table.render()

if pkg.requires:
self.line("")
Expand Down
7 changes: 6 additions & 1 deletion poetry/plugins/plugin_manager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import logging

from typing import List

import entrypoints

from .application_plugin import ApplicationPlugin
Expand All @@ -23,11 +25,14 @@ def load_plugins(self): # type: () -> None
if self._disable_plugins:
return

plugin_entrypoints = entrypoints.get_group_all("poetry.{}".format(self._type))
plugin_entrypoints = self.get_plugin_entry_points()

for entrypoint in plugin_entrypoints:
self._load_plugin_entrypoint(entrypoint)

def get_plugin_entry_points(self) -> List[entrypoints.EntryPoint]:
return entrypoints.get_group_all("poetry.{}".format(self._type))

def add_plugin(self, plugin): # type: (Plugin) -> None
if not isinstance(plugin, (Plugin, ApplicationPlugin)):
raise ValueError(
Expand Down
172 changes: 172 additions & 0 deletions tests/console/commands/plugin/test_show.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import pytest

from entrypoints import EntryPoint as _EntryPoint

from poetry.__version__ import __version__
from poetry.core.packages.package import Package
from poetry.factory import Factory
from poetry.plugins.application_plugin import ApplicationPlugin
from poetry.plugins.plugin import Plugin
from poetry.repositories.installed_repository import InstalledRepository
from poetry.repositories.pool import Pool
from poetry.utils.env import EnvManager


class EntryPoint(_EntryPoint):
def load(self):
if "ApplicationPlugin" in self.object_name:
return ApplicationPlugin

return Plugin


@pytest.fixture()
def tester(command_tester_factory):
return command_tester_factory("plugin show")


@pytest.fixture()
def installed():
repository = InstalledRepository()

repository.add_package(Package("poetry", __version__))

return repository


def configure_sources_factory(repo):
def _configure_sources(poetry, sources, config, io):
pool = Pool()
pool.add_repository(repo)
poetry.set_pool(pool)

return _configure_sources


@pytest.fixture(autouse=True)
def setup_mocks(mocker, env, repo, installed):
mocker.patch.object(EnvManager, "get_system_env", return_value=env)
mocker.patch.object(InstalledRepository, "load", return_value=installed)
mocker.patch.object(
Factory, "configure_sources", side_effect=configure_sources_factory(repo)
)


def test_show_displays_installed_plugins(app, tester, installed, mocker):
mocker.patch(
"entrypoints.get_group_all",
side_effect=[
[
EntryPoint(
"poetry-plugin",
"poetry_plugin.plugins:ApplicationPlugin",
"FirstApplicationPlugin",
)
],
[
EntryPoint(
"poetry-plugin",
"poetry_plugin.plugins:Plugin",
"FirstPlugin",
)
],
],
)

installed.add_package(Package("poetry-plugin", "1.2.3"))

tester.execute("")

expected = """
• poetry-plugin (1.2.3)
1 plugin and 1 application plugin
"""

assert tester.io.fetch_output() == expected


def test_show_displays_installed_plugins_with_multiple_plugins(
app, tester, installed, mocker
):
mocker.patch(
"entrypoints.get_group_all",
side_effect=[
[
EntryPoint(
"poetry-plugin",
"poetry_plugin.plugins:ApplicationPlugin",
"FirstApplicationPlugin",
),
EntryPoint(
"poetry-plugin",
"poetry_plugin.plugins:ApplicationPlugin",
"SecondApplicationPlugin",
),
],
[
EntryPoint(
"poetry-plugin",
"poetry_plugin.plugins:Plugin",
"FirstPlugin",
),
EntryPoint(
"poetry-plugin",
"poetry_plugin.plugins:Plugin",
"SecondPlugin",
),
],
],
)

installed.add_package(Package("poetry-plugin", "1.2.3"))

tester.execute("")

expected = """
• poetry-plugin (1.2.3)
2 plugins and 2 application plugins
"""

assert tester.io.fetch_output() == expected


def test_show_displays_installed_plugins_with_dependencies(
app, tester, installed, mocker
):
mocker.patch(
"entrypoints.get_group_all",
side_effect=[
[
EntryPoint(
"poetry-plugin",
"poetry_plugin.plugins:ApplicationPlugin",
"FirstApplicationPlugin",
)
],
[
EntryPoint(
"poetry-plugin",
"poetry_plugin.plugins:Plugin",
"FirstPlugin",
)
],
],
)

plugin = Package("poetry-plugin", "1.2.3")
plugin.add_dependency(Factory.create_dependency("foo", ">=1.2.3"))
plugin.add_dependency(Factory.create_dependency("bar", "<4.5.6"))
installed.add_package(plugin)

tester.execute("")

expected = """
• poetry-plugin (1.2.3)
1 plugin and 1 application plugin
Dependencies
- foo (>=1.2.3)
- bar (<4.5.6)
"""

assert tester.io.fetch_output() == expected

0 comments on commit a690ce7

Please sign in to comment.