mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-09 15:10:54 +00:00
[bug] Logic fix for plugins (#9934)
* Logic fix for plugins - Prevent tasks being run for disabled plugins * Adjust default value for "get_plugin" method * Fix return type * Update typing * Tweak unit test * Update unit tests * More test updates
This commit is contained in:
@ -30,7 +30,7 @@ class InvenTreeExchange(SimpleExchangeBackend):
|
||||
# Find the selected exchange rate plugin
|
||||
slug = get_global_setting('CURRENCY_UPDATE_PLUGIN', create=False)
|
||||
|
||||
plugin = registry.get_plugin(slug) if slug else None
|
||||
plugin = registry.get_plugin(slug, active=True) if slug else None
|
||||
|
||||
if not plugin:
|
||||
# Find the first active currency exchange plugin
|
||||
|
@ -35,7 +35,7 @@ def export_data(
|
||||
"""
|
||||
from plugin import registry
|
||||
|
||||
if (plugin := registry.get_plugin(plugin_key)) is None:
|
||||
if (plugin := registry.get_plugin(plugin_key, active=True)) is None:
|
||||
logger.warning("export_data: Plugin '%s' not found", plugin_key)
|
||||
return
|
||||
|
||||
|
@ -105,10 +105,10 @@ def process_event(plugin_slug, event, *args, **kwargs):
|
||||
This function is run by the background worker process.
|
||||
This function may queue multiple functions to be handled by the background worker.
|
||||
"""
|
||||
plugin = registry.get_plugin(plugin_slug)
|
||||
plugin = registry.get_plugin(plugin_slug, active=True)
|
||||
|
||||
if plugin is None: # pragma: no cover
|
||||
logger.error("Could not find matching plugin for '%s'", plugin_slug)
|
||||
logger.error("Could not find matching active plugin for '%s'", plugin_slug)
|
||||
return
|
||||
|
||||
logger.debug("Plugin '%s' is processing triggered event '%s'", plugin_slug, event)
|
||||
|
@ -26,10 +26,10 @@ def print_label(plugin_slug: str, **kwargs):
|
||||
"""
|
||||
logger.info("Plugin '%s' is printing a label", plugin_slug)
|
||||
|
||||
plugin = registry.get_plugin(plugin_slug)
|
||||
plugin = registry.get_plugin(plugin_slug, active=True)
|
||||
|
||||
if plugin is None: # pragma: no cover
|
||||
logger.error("Could not find matching plugin for '%s'", plugin_slug)
|
||||
logger.error("Could not find matching active plugin for '%s'", plugin_slug)
|
||||
return
|
||||
|
||||
try:
|
||||
|
@ -124,7 +124,7 @@ class LabelMixinTests(PrintTestMixins, InvenTreeAPITestCase):
|
||||
plugins = registry.with_mixin(PluginMixinEnum.LABELS)
|
||||
self.assertGreater(len(plugins), 0)
|
||||
|
||||
plugin = registry.get_plugin('samplelabelprinter')
|
||||
plugin = registry.get_plugin('samplelabelprinter', active=None)
|
||||
self.assertIsNotNone(plugin)
|
||||
config = plugin.plugin_config()
|
||||
|
||||
|
@ -16,9 +16,7 @@ class LocatePluginTests(InvenTreeAPITestCase):
|
||||
super().setUp()
|
||||
|
||||
# Activate plugin
|
||||
config = registry.get_plugin('samplelocate').plugin_config()
|
||||
config.active = True
|
||||
config.save()
|
||||
registry.set_plugin_state('samplelocate', True)
|
||||
|
||||
fixtures = ['category', 'part', 'location', 'stock']
|
||||
|
||||
|
@ -101,16 +101,18 @@ class PluginsRegistry:
|
||||
self.installed_apps = [] # Holds all added plugin_paths
|
||||
|
||||
@property
|
||||
def is_loading(self):
|
||||
def is_loading(self) -> bool:
|
||||
"""Return True if the plugin registry is currently loading."""
|
||||
return self.loading_lock.locked()
|
||||
|
||||
def get_plugin(self, slug, active=None, with_mixin=None):
|
||||
def get_plugin(
|
||||
self, slug: str, active: bool = True, with_mixin: Optional[str] = None
|
||||
) -> InvenTreePlugin:
|
||||
"""Lookup plugin by slug (unique key).
|
||||
|
||||
Args:
|
||||
slug (str): The slug of the plugin to look up.
|
||||
active (bool, optional): Filter by 'active' status of the plugin. If None, no filtering is applied. Defaults to None.
|
||||
active (bool, optional): Filter by 'active' status of the plugin. If None, no filtering is applied. Defaults to True.
|
||||
with_mixin (str, optional): Filter by mixin name. If None, no filtering is applied. Defaults to None.
|
||||
|
||||
Returns:
|
||||
@ -136,7 +138,7 @@ class PluginsRegistry:
|
||||
def get_plugin_config(self, slug: str, name: Union[str, None] = None):
|
||||
"""Return the matching PluginConfig instance for a given plugin.
|
||||
|
||||
Args:
|
||||
Arguments:
|
||||
slug: The plugin slug
|
||||
name: The plugin name (optional)
|
||||
"""
|
||||
@ -167,10 +169,10 @@ class PluginsRegistry:
|
||||
|
||||
return cfg
|
||||
|
||||
def set_plugin_state(self, slug, state):
|
||||
def set_plugin_state(self, slug: str, state: bool):
|
||||
"""Set the state(active/inactive) of a plugin.
|
||||
|
||||
Args:
|
||||
Arguments:
|
||||
slug (str): Plugin slug
|
||||
state (bool): Plugin state - true = active, false = inactive
|
||||
"""
|
||||
@ -374,7 +376,7 @@ class PluginsRegistry:
|
||||
# Ensure the lock is released always
|
||||
self.loading_lock.release()
|
||||
|
||||
def plugin_dirs(self):
|
||||
def plugin_dirs(self) -> list[str]:
|
||||
"""Construct a list of directories from where plugins can be loaded."""
|
||||
# Builtin plugins are *always* loaded
|
||||
dirs = ['plugin.builtin']
|
||||
|
@ -15,9 +15,7 @@ class EventPluginSampleTests(TestCase):
|
||||
def test_run_event(self):
|
||||
"""Check if the event is issued."""
|
||||
# Activate plugin
|
||||
config = registry.get_plugin('sampleevent').plugin_config()
|
||||
config.active = True
|
||||
config.save()
|
||||
registry.set_plugin_state('sampleevent', True)
|
||||
|
||||
InvenTreeSetting.set_setting('ENABLE_PLUGINS_EVENTS', True, change_user=None)
|
||||
|
||||
|
@ -13,9 +13,7 @@ class FilteredEventPluginSampleTests(TestCase):
|
||||
def test_run_event(self):
|
||||
"""Check if the event is issued."""
|
||||
# Activate plugin
|
||||
config = registry.get_plugin('filteredsampleevent').plugin_config()
|
||||
config.active = True
|
||||
config.save()
|
||||
registry.set_plugin_state('filteredsampleevent', True)
|
||||
|
||||
InvenTreeSetting.set_setting('ENABLE_PLUGINS_EVENTS', True, change_user=None)
|
||||
|
||||
@ -29,9 +27,7 @@ class FilteredEventPluginSampleTests(TestCase):
|
||||
def test_ignore_event(self):
|
||||
"""Check if the event is issued."""
|
||||
# Activate plugin
|
||||
config = registry.get_plugin('filteredsampleevent').plugin_config()
|
||||
config.active = True
|
||||
config.save()
|
||||
registry.set_plugin_state('filteredsampleevent', True)
|
||||
|
||||
InvenTreeSetting.set_setting('ENABLE_PLUGINS_EVENTS', True, change_user=None)
|
||||
|
||||
|
@ -14,9 +14,7 @@ class SampleIconPackPluginTests(InvenTreeAPITestCase):
|
||||
def test_get_icons_api(self):
|
||||
"""Check get icons api."""
|
||||
# Activate plugin
|
||||
config = registry.get_plugin('sampleicons').plugin_config()
|
||||
config.active = True
|
||||
config.save()
|
||||
registry.set_plugin_state('sampleicons', True)
|
||||
|
||||
response = self.get(reverse('api-icon-list'), expected_code=200)
|
||||
self.assertEqual(len(response.data), 2)
|
||||
|
@ -45,6 +45,7 @@ class SampleIntegrationPluginTests(InvenTreeTestCase):
|
||||
|
||||
def test_settings(self):
|
||||
"""Check the SettingsMixin.check_settings function."""
|
||||
registry.set_plugin_state('sample', True)
|
||||
plugin = registry.get_plugin('sample')
|
||||
self.assertIsNotNone(plugin)
|
||||
|
||||
@ -57,13 +58,19 @@ class SampleIntegrationPluginTests(InvenTreeTestCase):
|
||||
|
||||
def test_settings_validator(self):
|
||||
"""Test settings validator for plugins."""
|
||||
registry.set_plugin_state('sample', False)
|
||||
self.assertIsNone(registry.get_plugin('sample'))
|
||||
|
||||
registry.set_plugin_state('sample', True)
|
||||
plugin = registry.get_plugin('sample')
|
||||
self.assertIsNotNone(plugin)
|
||||
|
||||
valid_json = '{"ts": 13}'
|
||||
not_valid_json = '{"ts""13"}'
|
||||
|
||||
# no error, should pass validator
|
||||
plugin.set_setting('VALIDATOR_SETTING', valid_json)
|
||||
|
||||
# should throw an error
|
||||
# This should throw an error
|
||||
with self.assertRaises(ValidationError):
|
||||
plugin.set_setting('VALIDATOR_SETTING', not_valid_json)
|
||||
|
@ -76,7 +76,15 @@ class ExampleScheduledTaskPluginTests(TestCase):
|
||||
|
||||
def test_calling(self):
|
||||
"""Test calling of plugin functions by name."""
|
||||
# Check with right parameters
|
||||
# First, plugin is *not* enabled
|
||||
registry.set_plugin_state('schedule', False)
|
||||
|
||||
with self.assertRaises(AttributeError):
|
||||
self.assertEqual(call_plugin_function('schedule', 'member_func'), False)
|
||||
|
||||
registry.set_plugin_state('schedule', True)
|
||||
|
||||
# Should work now
|
||||
self.assertEqual(call_plugin_function('schedule', 'member_func'), False)
|
||||
|
||||
# Check with wrong key
|
||||
|
@ -8,7 +8,7 @@ from plugin.helpers import MixinNotImplementedError
|
||||
from plugin.mixins import LocateMixin
|
||||
|
||||
|
||||
class SampleLocatePlugintests(InvenTreeAPITestCase):
|
||||
class SampleLocatePluginTests(InvenTreeAPITestCase):
|
||||
"""Tests for SampleLocatePlugin."""
|
||||
|
||||
fixtures = ['location', 'category', 'part', 'stock']
|
||||
@ -16,7 +16,7 @@ class SampleLocatePlugintests(InvenTreeAPITestCase):
|
||||
def test_run_locator(self):
|
||||
"""Check if the event is issued."""
|
||||
# Activate plugin
|
||||
config = registry.get_plugin('samplelocate').plugin_config()
|
||||
config = registry.get_plugin('samplelocate', active=None).plugin_config()
|
||||
config.active = True
|
||||
config.save()
|
||||
|
||||
|
@ -15,7 +15,7 @@ class MailPluginSampleTests(TestCase):
|
||||
|
||||
def activate_plugin(self):
|
||||
"""Activate the sample mail plugin."""
|
||||
config = registry.get_plugin('samplemail').plugin_config()
|
||||
config = registry.get_plugin('samplemail', active=None).plugin_config()
|
||||
config.active = True
|
||||
config.save()
|
||||
|
||||
|
@ -217,6 +217,7 @@ class RegistryTests(TestCase):
|
||||
with mock.patch.dict(os.environ, envs):
|
||||
# Reload to rediscover plugins
|
||||
registry.reload_plugins(full_reload=True, collect=True)
|
||||
registry.set_plugin_state('simple', True)
|
||||
|
||||
# Depends on the meta set in InvenTree/plugin/mock/simple:SimplePlugin
|
||||
plg = registry.get_plugin('simple')
|
||||
@ -264,7 +265,7 @@ class RegistryTests(TestCase):
|
||||
registry.reload_plugins(full_reload=True, collect=True)
|
||||
|
||||
# Test that plugin was installed
|
||||
plg = registry.get_plugin('zapier')
|
||||
plg = registry.get_plugin('zapier', active=None)
|
||||
self.assertEqual(plg.slug, 'zapier')
|
||||
self.assertEqual(plg.name, 'inventree_zapier')
|
||||
|
||||
|
@ -68,7 +68,7 @@ def print_labels(
|
||||
model = template.get_model()
|
||||
items = model.objects.filter(pk__in=item_ids)
|
||||
|
||||
plugin = registry.get_plugin(plugin_slug)
|
||||
plugin = registry.get_plugin(plugin_slug, active=True)
|
||||
|
||||
if not plugin:
|
||||
logger.warning("Label printing plugin '%s' not found", plugin_slug)
|
||||
|
@ -357,12 +357,9 @@ class PrintTestMixins:
|
||||
|
||||
def do_activate_plugin(self):
|
||||
"""Activate the 'samplelabel' plugin."""
|
||||
registry.set_plugin_state(self.plugin_ref, True)
|
||||
plugin = registry.get_plugin(self.plugin_ref)
|
||||
self.assertIsNotNone(plugin)
|
||||
config = plugin.plugin_config()
|
||||
self.assertIsNotNone(config)
|
||||
config.active = True
|
||||
config.save()
|
||||
|
||||
def run_print_test(self, qs, model_type, label: bool = True):
|
||||
"""Run tests on single and multiple page printing.
|
||||
|
Reference in New Issue
Block a user