Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More refactoring for plugin manager. #13118

Merged
merged 10 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 22 additions & 24 deletions conda/plugins/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,24 @@
else:
return f"{prefix}.{plugin.__class__.__qualname__}[{id(plugin)}]"

def register(self, plugin, name: str | None = None) -> str | None:
"""
Call :meth:`pluggy.PluginManager.register` and return the result or
ignore errors raised, except ``ValueError``, which means the plugin
had already been registered.
"""
try:
# register plugin but ignore ValueError since that means
# the plugin has already been registered
return super().register(plugin, name=name)
except ValueError:
return None
except Exception as err:
raise PluginError(

Check warning on line 90 in conda/plugins/manager.py

View check run for this annotation

Codecov / codecov/patch

conda/plugins/manager.py#L89-L90

Added lines #L89 - L90 were not covered by tests
f"Error while loading conda plugin: "
f"{name or self.get_canonical_name(plugin)} ({err})"
)

def load_plugins(self, *plugins) -> int:
"""
Load the provided list of plugins and fail gracefully on error.
Expand All @@ -82,18 +100,8 @@
"""
count = 0
for plugin in plugins:
try:
# register plugin
# extracts canonical name from plugin, checks for duplicates,
# and if blocked
if self.register(plugin):
# successfully registered a plugin
count += 1
except ValueError as err:
raise PluginError(
f"Error while loading first-party conda plugin: "
f"{self.get_canonical_name(plugin)} ({err})"
)
if self.register(plugin):
count += 1
return count

def load_entrypoints(self, group: str, name: str | None = None) -> int:
Expand Down Expand Up @@ -126,18 +134,8 @@
)
continue

try:
# register plugin
# extracts canonical name from plugin, checks for duplicates,
# and if blocked
if self.register(plugin):
# successfully registered a plugin
count += 1
except ValueError as err:
raise PluginError(
f"Error while loading third-party conda plugin: "
f"{self.get_canonical_name(plugin)} ({err})"
)
if self.register(plugin):
count += 1
return count

@overload
Expand Down
40 changes: 13 additions & 27 deletions tests/plugins/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,15 @@ def conda_virtual_packages(*args):


def test_load_without_plugins(plugin_manager: CondaPluginManager):
plugin_names = plugin_manager.load_plugins()
assert plugin_names == 0
assert plugin_manager.load_plugins() == 0


def test_load_two_plugins_one_impls(plugin_manager: CondaPluginManager):
plugin_names = plugin_manager.load_plugins(this_module)
assert plugin_names == 1
assert plugin_manager.load_plugins(this_module) == 1
assert plugin_manager.get_plugins() == {this_module}
assert plugin_manager.hook.conda_solvers.get_hookimpls() == []

plugin_names = plugin_manager.load_plugins(VerboseSolverPlugin)
assert plugin_names == 1
assert plugin_manager.load_plugins(VerboseSolverPlugin) == 1
assert plugin_manager.get_plugins() == {this_module, VerboseSolverPlugin}

hooks_impls = plugin_manager.hook.conda_solvers.get_hookimpls()
Expand All @@ -81,7 +78,7 @@ def test_get_hook_results(plugin_manager: CondaPluginManager):
assert plugin_manager.get_hook_results(name) == []

# loading the archspec plugin module and make sure it was loaded correctly
plugin_manager.load_plugins(virtual_packages.archspec)
assert plugin_manager.load_plugins(virtual_packages.archspec) == 1
hook_result = plugin_manager.get_hook_results(name)
assert len(hook_result) == 1
assert hook_result[0].name == "archspec"
Expand All @@ -104,14 +101,7 @@ def conda_virtual_packages():


def test_load_plugins_error(plugin_manager: CondaPluginManager):
# first load the plugin once
plugin_manager.load_plugins(VerboseSolverPlugin)
# then try again to trigger a PluginError via the `ValueError` that
# pluggy.PluginManager.register throws on duplicate plugins
with pytest.raises(
PluginError, match="Error while loading first-party conda plugin"
):
plugin_manager.load_plugins(VerboseSolverPlugin)
assert plugin_manager.load_plugins(VerboseSolverPlugin) == 1
assert plugin_manager.get_plugins() == {VerboseSolverPlugin}


Expand Down Expand Up @@ -150,15 +140,11 @@ def test_load_entrypoints_blocked(plugin_manager: CondaPluginManager):

def test_load_entrypoints_register_valueerror(plugin_manager: CondaPluginManager):
"""
Cover check when self.register() raises ValueError.
Cover check when self.register() raises ValueError because the plugin
was loaded already.
"""

def raises_value_error(*args):
raise ValueError("bad plugin?")

plugin_manager.register = raises_value_error
with pytest.raises(PluginError):
plugin_manager.load_entrypoints("test_plugin", "success")
assert plugin_manager.load_entrypoints("test_plugin", "success") == 1
assert plugin_manager.load_entrypoints("test_plugin", "success") == 0


def test_unknown_solver(plugin_manager: CondaPluginManager):
Expand All @@ -173,7 +159,7 @@ def test_known_solver(plugin_manager: CondaPluginManager):
"""
Cover getting a solver that exists.
"""
plugin_manager.load_plugins(VerboseSolverPlugin)
assert plugin_manager.load_plugins(VerboseSolverPlugin) == 1
assert plugin_manager.get_solver_backend("verbose-classic") == VerboseSolver


Expand Down Expand Up @@ -214,17 +200,17 @@ def test_disable_external_plugins(plugin_manager: CondaPluginManager, plugin: ob


def test_get_virtual_packages(plugin_manager: CondaPluginManager):
plugin_manager.load_plugins(DummyVirtualPackagePlugin)
assert plugin_manager.load_plugins(DummyVirtualPackagePlugin) == 1
assert plugin_manager.get_virtual_packages() == (DummyVirtualPackage,)


def test_get_virtual_packages_no_name(plugin_manager: CondaPluginManager):
plugin_manager.load_plugins(NoNameVirtualPackagePlugin)
assert plugin_manager.load_plugins(NoNameVirtualPackagePlugin) == 1
with pytest.raises(PluginError, match="Invalid plugin names"):
plugin_manager.get_virtual_packages()


def test_get_solvers(plugin_manager: CondaPluginManager):
plugin_manager.load_plugins(VerboseSolverPlugin)
assert plugin_manager.load_plugins(VerboseSolverPlugin) == 1
assert plugin_manager.get_plugins() == {VerboseSolverPlugin}
assert plugin_manager.get_solvers() == {"verbose-classic": VerboseCondaSolver}
11 changes: 4 additions & 7 deletions tests/plugins/test_subcommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from conda.auxlib.ish import dals
from conda.base.context import context
from conda.cli.conda_argparse import BUILTIN_COMMANDS, generate_parser
from conda.exceptions import PluginError
from conda.plugins.types import CondaSubcommand
from conda.testing import CondaCLIFixture

Expand Down Expand Up @@ -76,14 +75,12 @@ def test_duplicated(plugin_manager, conda_cli: CondaCLIFixture):
plugin = SubcommandPlugin(name="custom", summary="Summary.")
assert plugin_manager.load_plugins(plugin) == 1

# invalid, identical plugins
with pytest.raises(PluginError, match="Error while loading first-party"):
plugin_manager.load_plugins(plugin)
# invalid, identical plugins, error ignored
assert plugin_manager.load_plugins(plugin) == 0

# invalid, similar plugins
# invalid, similar plugins, error ignored
plugin2 = SubcommandPlugin(name="custom", summary="Summary.")
with pytest.raises(PluginError, match="Error while loading first-party"):
plugin_manager.load_plugins(plugin2)
assert plugin_manager.load_plugins(plugin2) == 0


@pytest.mark.parametrize("command", BUILTIN_COMMANDS)
Expand Down
Loading