Coverage for src/backend/InvenTree/plugin/base/integration/SettingsMixin.py: 51%
80 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 17:47 +0000
1"""Plugin mixin class for SettingsMixin."""
3from typing import TYPE_CHECKING, Any, Optional
5from django.db.utils import OperationalError, ProgrammingError
7import structlog
9from plugin import PluginMixinEnum
11logger = structlog.get_logger('inventree')
13# import only for typechecking, otherwise this throws a model is unready error
14if TYPE_CHECKING: 14 ↛ 15line 14 didn't jump to line 15 because the condition on line 14 was never true
15 from django.contrib.auth.models import User
17 from common.models import SettingsKeyType
18else:
20 class User:
21 """Dummy class, so that python throws no error."""
23 class SettingsKeyType:
24 """Dummy class, so that python throws no error."""
27class SettingsMixin:
28 """Mixin that enables global settings for the plugin."""
30 SETTINGS: dict[str, SettingsKeyType] = {}
31 USER_SETTINGS: dict[str, SettingsKeyType] = {}
33 class MixinMeta:
34 """Meta for mixin."""
36 MIXIN_NAME = 'Settings'
38 def __init__(self):
39 """Register mixin."""
40 super().__init__()
41 self.add_mixin(PluginMixinEnum.SETTINGS, 'has_settings', __class__)
42 self.settings = getattr(self, 'SETTINGS', {})
43 self.user_settings = getattr(self, 'USER_SETTINGS', {})
45 @classmethod
46 def _activate_mixin(cls, registry, plugins, *args, **kwargs):
47 """Activate plugin settings.
49 Add all defined settings form the plugins to a unified dict in the registry.
50 This dict is referenced by the PluginSettings for settings definitions.
51 """
52 logger.debug('Activating plugin settings')
54 registry.mixins_settings = {}
55 registry.mixins_user_settings = {}
57 for slug, plugin in plugins:
58 if plugin.mixin_enabled(PluginMixinEnum.SETTINGS):
59 plugin_setting = plugin.settings or {}
60 registry.mixins_settings[slug] = plugin_setting
62 plugin_user_setting = plugin.user_settings or {}
63 registry.mixins_user_settings[slug] = plugin_user_setting
65 @classmethod
66 def _deactivate_mixin(cls, registry, **kwargs):
67 """Deactivate all plugin settings."""
68 logger.debug('Deactivating plugin settings')
69 # clear settings cache
70 registry.mixins_settings = {}
72 @property
73 def has_settings(self):
74 """Does this plugin use custom global settings."""
75 return bool(self.settings) or bool(self.user_settings)
77 def get_setting(
78 self, key: str, cache: bool = False, backup_value: Any = None
79 ) -> Any:
80 """Return the 'value' of the setting associated with this plugin.
82 Arguments:
83 key: The 'name' of the setting value to be retrieved
84 cache: Whether to use cached value (default = False)
85 backup_value: A backup value to return if the setting is not found
86 """
87 from plugin.models import PluginSetting
89 return PluginSetting.get_setting(
90 key, plugin=self.plugin_config(), cache=cache, backup_value=backup_value
91 )
93 def set_setting(
94 self, key: str, value: Any, user: Optional[User] = None, **kwargs
95 ) -> None:
96 """Set plugin setting value by key.
98 Arguments:
99 key: The 'name' of the setting value to be set
100 value: The value to be set for the setting
101 user: The user who is making the change (optional)
102 """
103 from plugin.models import PluginSetting
104 from plugin.registry import registry
106 try:
107 plugin = registry.get_plugin_config(self.plugin_slug(), self.plugin_name())
108 except (OperationalError, ProgrammingError): # pragma: no cover
109 plugin = None
111 if not plugin: # pragma: no cover
112 # Cannot find associated plugin model, return
113 logger.error("Plugin configuration not found for plugin '%s'", self.slug)
114 return
116 PluginSetting.set_setting(key, value, plugin=plugin)
118 def get_user_setting(
119 self, key: str, user: User, cache: bool = False, backup_value: Any = None
120 ) -> Any:
121 """Return the 'value' of the user setting associated with this plugin.
123 Arguments:
124 key: The 'name' of the user setting value to be retrieved
125 user: The user for which the setting is to be retrieved
126 cache: Whether to use cached value (default = False)
127 backup_value: A backup value to return if the setting is not found
128 """
129 from plugin.models import PluginUserSetting
131 return PluginUserSetting.get_setting(
132 key,
133 plugin=self.plugin_config(),
134 user=user,
135 cache=cache,
136 backup_value=backup_value,
137 settings=self.user_settings,
138 )
140 def set_user_setting(self, key: str, value: Any, user: User) -> None:
141 """Set user setting value by key.
143 Arguments:
144 key: The 'name' of the user setting value to be set
145 value: The value to be set for the user setting
146 user: The user for which the setting is to be set
147 """
148 from plugin.models import PluginUserSetting
149 from plugin.registry import registry
151 try:
152 plugin = registry.get_plugin_config(self.plugin_slug(), self.plugin_name())
153 except (OperationalError, ProgrammingError):
154 plugin = None
156 if not plugin: # pragma: no cover
157 # Cannot find associated plugin model, return
158 logger.error("Plugin configuration not found for plugin '%s'", self.slug)
159 return
161 PluginUserSetting.set_setting(key, value, user, user=user, plugin=plugin)
163 def check_settings(self):
164 """Check if all required settings for this machine are defined.
166 Warning: This method cannot be used in the __init__ function of the plugin
168 Returns:
169 is_valid: Are all required settings defined
170 missing_settings: List of all settings that are missing (empty if is_valid is 'True')
171 """
172 from plugin.models import PluginSetting
174 return PluginSetting.check_all_settings(
175 settings_definition=self.settings, plugin=self.plugin_config()
176 )
178 def get_settings_dict(self) -> dict:
179 """Return a dictionary of all settings for this plugin.
181 - For each setting, return <key>: <value> pair.
182 - If the setting is not defined, return the default value (if defined).
184 Returns:
185 dict: Dictionary of all settings for this plugin
186 """
187 from plugin.models import PluginSetting
189 keys = self.settings.keys()
191 settings = PluginSetting.objects.filter(
192 plugin=self.plugin_config(), key__in=keys
193 )
195 settings_dict = {}
197 for setting in settings:
198 settings_dict[setting.key] = setting.value
200 # Add any missing settings
201 for key in keys:
202 if key not in settings_dict:
203 settings_dict[key] = self.settings[key].get('default')
205 return settings_dict