Cleanup plugin mixin registry (#4790)

* collect mixins dynamically

* remove unfinsihed option to reorder mixins

* clean up settings

* fix text

* fix mixin lookup

* stupid error

* fix assertations

* use regustered function instead of private dict

* switch to dict for reg

* fix test

* makke sure mixins also works with class

* cleanup

* fix reqs

* fix test assertations
This commit is contained in:
Matthias Mair 2023-05-12 14:00:25 +02:00 committed by GitHub
parent 17057f4266
commit 017ccaa27a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 20 deletions

View File

@ -24,9 +24,9 @@ class BaseMixinDefinition:
def test_mixin_name(self):
"""Test that the mixin registers itseld correctly."""
# mixin name
self.assertIn(self.MIXIN_NAME, [item['key'] for item in self.mixin.registered_mixins])
self.assertIn(self.MIXIN_NAME, {item['key'] for item in self.mixin.registered_mixins.values()})
# human name
self.assertIn(self.MIXIN_HUMAN_NAME, [item['human_name'] for item in self.mixin.registered_mixins])
self.assertIn(self.MIXIN_HUMAN_NAME, {item['human_name'] for item in self.mixin.registered_mixins.values()})
class SettingsMixinTest(BaseMixinDefinition, InvenTreeTestCase):

View File

@ -1,5 +1,6 @@
"""Plugin model definitions."""
import inspect
import warnings
from django.conf import settings
@ -58,7 +59,9 @@ class PluginConfig(models.Model):
def mixins(self):
"""Returns all registered mixins."""
try:
return self.plugin._mixinreg
if inspect.isclass(self.plugin):
return self.plugin.get_registered_mixins(self, with_base=True, with_cls=False)
return self.plugin.get_registered_mixins(with_base=True, with_cls=False)
except (AttributeError, ValueError): # pragma: no cover
return {}
@ -166,7 +169,9 @@ class PluginSetting(common.models.BaseInvenTreeSetting):
if issubclass(plugin.__class__, InvenTreePlugin):
plugin = plugin.plugin_config()
kwargs['settings'] = registry.mixins_settings.get(plugin.key, {})
mixin_settings = getattr(registry, 'mixins_settings')
if mixin_settings:
kwargs['settings'] = mixin_settings.get(plugin.key, {})
return super().get_setting_definition(key, **kwargs)

View File

@ -161,19 +161,29 @@ class MixinBase:
self._mixinreg[key] = {
'key': key,
'human_name': human_name,
'cls': cls,
}
def get_registered_mixins(self, with_base: bool = False, with_cls: bool = True):
"""Get all registered mixins for the plugin."""
mixins = getattr(self, '_mixinreg', None)
if not mixins:
return {}
mixins = mixins.copy()
# filter out base
if not with_base and 'base' in mixins:
del mixins['base']
# Do not return the mixin class if flas is set
if not with_cls:
return {key: {k: v for k, v in mixin.items() if k != 'cls'} for key, mixin in mixins.items()}
return mixins
@property
def registered_mixins(self, with_base: bool = False):
"""Get all registered mixins for the plugin."""
mixins = getattr(self, '_mixinreg', None)
if mixins:
# filter out base
if not with_base and 'base' in mixins:
del mixins['base']
# only return dict
mixins = list(mixins.values())
return mixins
return self.get_registered_mixins(with_base=with_base)
class VersionMixin:

View File

@ -42,7 +42,7 @@ class PluginsRegistry:
DEFAULT_MIXIN_ORDER = [SettingsMixin, ScheduleMixin, AppMixin, UrlsMixin]
def __init__(self, mixin_order: list = None) -> None:
def __init__(self) -> None:
"""Initialize registry.
Set up all needed references for internal and external states.
@ -53,6 +53,7 @@ class PluginsRegistry:
self.plugins_full: Dict[str, InvenTreePlugin] = {} # List of all plugin instances
self.plugin_modules: List(InvenTreePlugin) = [] # Holds all discovered plugins
self.mixin_modules: Dict[str, any] = {} # Holds all discovered mixins
self.errors = {} # Holds discovering errors
@ -63,10 +64,6 @@ class PluginsRegistry:
self.installed_apps = [] # Holds all added plugin_paths
# mixins
self.mixins_settings = {}
self.mixin_order = mixin_order or self.DEFAULT_MIXIN_ORDER
def get_plugin(self, slug):
"""Lookup plugin by slug (unique key)."""
if slug not in self.plugins:
@ -322,6 +319,15 @@ class PluginsRegistry:
return collected_plugins
def discover_mixins(self):
"""Discover all mixins from plugins and register them."""
collected_mixins = {}
for plg in self.plugins.values():
collected_mixins.update(plg.get_registered_mixins())
self.mixin_modules = collected_mixins
def install_plugin_file(self):
"""Make sure all plugins are installed in the current environment."""
if settings.PLUGIN_FILE_CHECKED:
@ -468,6 +474,17 @@ class PluginsRegistry:
else: # pragma: no cover
safe_reference(plugin=plg, key=plg_key, active=False)
def __get_mixin_order(self):
"""Returns a list of mixin classes, in the order that they should be activated."""
# Preset list of mixins
order = self.DEFAULT_MIXIN_ORDER
# Append mixins that are not defined in the default list
order += [m.get('cls') for m in self.mixin_modules.values() if m.get('cls') not in order]
# Final list of mixins
return order
def _activate_plugins(self, force_reload=False, full_reload: bool = False):
"""Run activation functions for all plugins.
@ -475,11 +492,14 @@ class PluginsRegistry:
force_reload (bool, optional): Also reload base apps. Defaults to False.
full_reload (bool, optional): Reload everything - including plugin mechanism. Defaults to False.
"""
# activate integrations
# Collect mixins
self.discover_mixins()
# Activate integrations
plugins = self.plugins.items()
logger.info(f'Found {len(plugins)} active plugins')
for mixin in self.mixin_order:
for mixin in self.__get_mixin_order():
if hasattr(mixin, '_activate_mixin'):
mixin._activate_mixin(self, plugins, force_reload=force_reload, full_reload=full_reload)
@ -491,7 +511,7 @@ class PluginsRegistry:
Args:
force_reload (bool, optional): Also reload base apps. Defaults to False.
"""
for mixin in self.mixin_order:
for mixin in reversed(self.__get_mixin_order()):
if hasattr(mixin, '_deactivate_mixin'):
mixin._deactivate_mixin(self, force_reload=force_reload)