Merge pull request #1399 from ynput/enhancement/plugin-paths-interface

Addons: Plugin paths interface
This commit is contained in:
Jakub Trllo 2025-08-04 10:19:00 +02:00 committed by GitHub
commit add5a5bf79
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 62 additions and 19 deletions

View file

@ -8,6 +8,7 @@ import inspect
import logging
import threading
import collections
import warnings
from uuid import uuid4
from abc import ABC, abstractmethod
from typing import Optional
@ -815,10 +816,26 @@ class AddonsManager:
Unknown keys are logged out.
Deprecated:
Use targeted methods 'collect_launcher_action_paths',
'collect_create_plugin_paths', 'collect_load_plugin_paths',
'collect_publish_plugin_paths' and
'collect_inventory_action_paths' to collect plugin paths.
Returns:
dict: Output is dictionary with keys "publish", "create", "load",
"actions" and "inventory" each containing list of paths.
"""
warnings.warn(
"Used deprecated method 'collect_plugin_paths'. Please use"
" targeted methods 'collect_launcher_action_paths',"
" 'collect_create_plugin_paths', 'collect_load_plugin_paths'"
" 'collect_publish_plugin_paths' and"
" 'collect_inventory_action_paths'",
DeprecationWarning,
stacklevel=2
)
# Output structure
output = {
"publish": [],
@ -874,23 +891,27 @@ class AddonsManager:
if not isinstance(addon, IPluginPaths):
continue
paths = None
method = getattr(addon, method_name)
try:
paths = method(*args, **kwargs)
except Exception:
self.log.warning(
(
"Failed to get plugin paths from addon"
" '{}' using '{}'."
).format(addon.__class__.__name__, method_name),
f" '{addon.name}' using '{method_name}'.",
exc_info=True
)
if not paths:
continue
if paths:
# Convert to list if value is not list
if not isinstance(paths, (list, tuple, set)):
if isinstance(paths, str):
paths = [paths]
self.log.warning(
f"Addon '{addon.name}' returned invalid output type"
f" from '{method_name}'."
f" Got 'str' expected 'list[str]'."
)
output.extend(paths)
return output

View file

@ -1,6 +1,7 @@
"""Addon interfaces for AYON."""
from __future__ import annotations
import warnings
from abc import ABCMeta, abstractmethod
from typing import TYPE_CHECKING, Callable, Optional, Type
@ -39,26 +40,29 @@ class AYONInterface(metaclass=_AYONInterfaceMeta):
class IPluginPaths(AYONInterface):
"""Addon has plugin paths to return.
"""Addon wants to register plugin paths."""
Expected result is dictionary with keys "publish", "create", "load",
"actions" or "inventory" and values as list or string.
{
"publish": ["path/to/publish_plugins"]
}
"""
@abstractmethod
def get_plugin_paths(self) -> dict[str, list[str]]:
"""Return plugin paths for addon.
This method was abstract (required) in the past, so raise the required
'core' addon version when 'get_plugin_paths' is removed from
addon.
Deprecated:
Please implement specific methods 'get_create_plugin_paths',
'get_load_plugin_paths', 'get_inventory_action_paths' and
'get_publish_plugin_paths' to return plugin paths.
Returns:
dict[str, list[str]]: Plugin paths for addon.
"""
return {}
def _get_plugin_paths_by_type(
self, plugin_type: str) -> list[str]:
self, plugin_type: str
) -> list[str]:
"""Get plugin paths by type.
Args:
@ -78,6 +82,24 @@ class IPluginPaths(AYONInterface):
if not isinstance(paths, (list, tuple, set)):
paths = [paths]
new_function_name = "get_launcher_action_paths"
if plugin_type == "create":
new_function_name = "get_create_plugin_paths"
elif plugin_type == "load":
new_function_name = "get_load_plugin_paths"
elif plugin_type == "publish":
new_function_name = "get_publish_plugin_paths"
elif plugin_type == "inventory":
new_function_name = "get_inventory_action_paths"
warnings.warn(
f"Addon '{self.name}' returns '{plugin_type}' paths using"
" 'get_plugin_paths' method. Please implement"
f" '{new_function_name}' instead.",
DeprecationWarning,
stacklevel=2
)
return paths
def get_launcher_action_paths(self) -> list[str]: