mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
fix docstrings 7
This commit is contained in:
parent
bd4da62964
commit
d3d0b76c58
@ -1,6 +1,4 @@
|
||||
"""
|
||||
JSON API for the plugin app
|
||||
"""
|
||||
"""JSON API for the plugin app"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import include, re_path
|
||||
@ -20,7 +18,7 @@ from plugin.registry import registry
|
||||
|
||||
|
||||
class PluginList(generics.ListAPIView):
|
||||
""" API endpoint for list of PluginConfig objects
|
||||
"""API endpoint for list of PluginConfig objects
|
||||
|
||||
- GET: Return a list of all PluginConfig objects
|
||||
"""
|
||||
@ -79,7 +77,7 @@ class PluginList(generics.ListAPIView):
|
||||
|
||||
|
||||
class PluginDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
""" API detail endpoint for PluginConfig object
|
||||
"""API detail endpoint for PluginConfig object
|
||||
|
||||
get:
|
||||
Return a single PluginConfig object
|
||||
@ -96,9 +94,8 @@ class PluginDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
|
||||
|
||||
class PluginInstall(generics.CreateAPIView):
|
||||
"""
|
||||
Endpoint for installing a new plugin
|
||||
"""
|
||||
"""Endpoint for installing a new plugin"""
|
||||
|
||||
queryset = PluginConfig.objects.none()
|
||||
serializer_class = PluginSerializers.PluginConfigInstallSerializer
|
||||
|
||||
@ -115,8 +112,7 @@ class PluginInstall(generics.CreateAPIView):
|
||||
|
||||
|
||||
class PluginSettingList(generics.ListAPIView):
|
||||
"""
|
||||
List endpoint for all plugin related settings.
|
||||
"""List endpoint for all plugin related settings.
|
||||
|
||||
- read only
|
||||
- only accessible by staff users
|
||||
@ -140,8 +136,7 @@ class PluginSettingList(generics.ListAPIView):
|
||||
|
||||
|
||||
class PluginSettingDetail(generics.RetrieveUpdateAPIView):
|
||||
"""
|
||||
Detail endpoint for a plugin-specific setting.
|
||||
"""Detail endpoint for a plugin-specific setting.
|
||||
|
||||
Note that these cannot be created or deleted via the API
|
||||
"""
|
||||
@ -150,13 +145,11 @@ class PluginSettingDetail(generics.RetrieveUpdateAPIView):
|
||||
serializer_class = PluginSerializers.PluginSettingSerializer
|
||||
|
||||
def get_object(self):
|
||||
"""
|
||||
Lookup the plugin setting object, based on the URL.
|
||||
The URL provides the 'slug' of the plugin, and the 'key' of the setting.
|
||||
"""Lookup the plugin setting object, based on the URL.
|
||||
|
||||
The URL provides the 'slug' of the plugin, and the 'key' of the setting.
|
||||
Both the 'slug' and 'key' must be valid, else a 404 error is raised
|
||||
"""
|
||||
|
||||
plugin_slug = self.kwargs['plugin']
|
||||
key = self.kwargs['key']
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
"""
|
||||
Import helper for events
|
||||
"""
|
||||
"""Import helper for events"""
|
||||
|
||||
from plugin.base.event.events import (process_event, register_event,
|
||||
trigger_event)
|
||||
|
@ -1,6 +1,5 @@
|
||||
"""
|
||||
Helpers for plugin app
|
||||
"""
|
||||
"""Helpers for plugin app"""
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
@ -20,9 +19,8 @@ logger = logging.getLogger('inventree')
|
||||
|
||||
# region logging / errors
|
||||
class IntegrationPluginError(Exception):
|
||||
"""
|
||||
Error that encapsulates another error and adds the path / reference of the raising plugin
|
||||
"""
|
||||
"""Error that encapsulates another error and adds the path / reference of the raising plugin"""
|
||||
|
||||
def __init__(self, path, message):
|
||||
self.path = path
|
||||
self.message = message
|
||||
@ -32,24 +30,20 @@ class IntegrationPluginError(Exception):
|
||||
|
||||
|
||||
class MixinImplementationError(ValueError):
|
||||
"""
|
||||
Error if mixin was implemented wrong in plugin
|
||||
"""Error if mixin was implemented wrong in plugin
|
||||
|
||||
Mostly raised if constant is missing
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class MixinNotImplementedError(NotImplementedError):
|
||||
"""
|
||||
Error if necessary mixin function was not overwritten
|
||||
"""
|
||||
"""Error if necessary mixin function was not overwritten"""
|
||||
pass
|
||||
|
||||
|
||||
def log_error(error, reference: str = 'general'):
|
||||
"""
|
||||
Log an plugin error
|
||||
"""
|
||||
"""Log an plugin error"""
|
||||
from plugin import registry
|
||||
|
||||
# make sure the registry is set up
|
||||
@ -61,9 +55,7 @@ def log_error(error, reference: str = 'general'):
|
||||
|
||||
|
||||
def handle_error(error, do_raise: bool = True, do_log: bool = True, log_name: str = ''):
|
||||
"""
|
||||
Handles an error and casts it as an IntegrationPluginError
|
||||
"""
|
||||
"""Handles an error and casts it as an IntegrationPluginError"""
|
||||
package_path = traceback.extract_tb(error.__traceback__)[-1].filename
|
||||
install_path = sysconfig.get_paths()["purelib"]
|
||||
try:
|
||||
@ -99,9 +91,7 @@ def handle_error(error, do_raise: bool = True, do_log: bool = True, log_name: st
|
||||
|
||||
# region git-helpers
|
||||
def get_git_log(path):
|
||||
"""
|
||||
Get dict with info of the last commit to file named in path
|
||||
"""
|
||||
"""Get dict with info of the last commit to file named in path"""
|
||||
from plugin import registry
|
||||
|
||||
output = None
|
||||
@ -122,8 +112,7 @@ def get_git_log(path):
|
||||
|
||||
|
||||
def check_git_version():
|
||||
"""returns if the current git version supports modern features"""
|
||||
|
||||
"""Returns if the current git version supports modern features"""
|
||||
# get version string
|
||||
try:
|
||||
output = str(subprocess.check_output(['git', '--version'], cwd=os.path.dirname(settings.BASE_DIR)), 'utf-8')
|
||||
@ -143,13 +132,11 @@ def check_git_version():
|
||||
|
||||
|
||||
class GitStatus:
|
||||
"""
|
||||
Class for resolving git gpg singing state
|
||||
"""
|
||||
"""Class for resolving git gpg singing state"""
|
||||
|
||||
class Definition:
|
||||
"""
|
||||
Definition of a git gpg sing state
|
||||
"""
|
||||
"""Definition of a git gpg sing state"""
|
||||
|
||||
key: str = 'N'
|
||||
status: int = 2
|
||||
msg: str = ''
|
||||
@ -172,8 +159,7 @@ class GitStatus:
|
||||
|
||||
# region plugin finders
|
||||
def get_modules(pkg):
|
||||
"""get all modules in a package"""
|
||||
|
||||
"""Get all modules in a package"""
|
||||
context = {}
|
||||
for loader, name, ispkg in pkgutil.walk_packages(pkg.__path__):
|
||||
try:
|
||||
@ -195,18 +181,16 @@ def get_modules(pkg):
|
||||
|
||||
|
||||
def get_classes(module):
|
||||
"""get all classes in a given module"""
|
||||
"""Get all classes in a given module"""
|
||||
return inspect.getmembers(module, inspect.isclass)
|
||||
|
||||
|
||||
def get_plugins(pkg, baseclass):
|
||||
"""
|
||||
Return a list of all modules under a given package.
|
||||
"""Return a list of all modules under a given package.
|
||||
|
||||
- Modules must be a subclass of the provided 'baseclass'
|
||||
- Modules must have a non-empty NAME parameter
|
||||
"""
|
||||
|
||||
plugins = []
|
||||
|
||||
modules = get_modules(pkg)
|
||||
@ -225,10 +209,7 @@ def get_plugins(pkg, baseclass):
|
||||
|
||||
# region templates
|
||||
def render_template(plugin, template_file, context=None):
|
||||
"""
|
||||
Locate and render a template file, available in the global template context.
|
||||
"""
|
||||
|
||||
"""Locate and render a template file, available in the global template context."""
|
||||
try:
|
||||
tmp = template.loader.get_template(template_file)
|
||||
except template.TemplateDoesNotExist:
|
||||
@ -247,10 +228,7 @@ def render_template(plugin, template_file, context=None):
|
||||
|
||||
|
||||
def render_text(text, context=None):
|
||||
"""
|
||||
Locate a raw string with provided context
|
||||
"""
|
||||
|
||||
"""Locate a raw string with provided context"""
|
||||
ctx = template.Context(context)
|
||||
|
||||
return template.Template(text).render(ctx)
|
||||
|
@ -1,6 +1,4 @@
|
||||
"""
|
||||
Plugin model definitions
|
||||
"""
|
||||
"""Plugin model definitions"""
|
||||
|
||||
import warnings
|
||||
|
||||
@ -14,8 +12,7 @@ from plugin import InvenTreePlugin, registry
|
||||
|
||||
|
||||
class MetadataMixin(models.Model):
|
||||
"""
|
||||
Model mixin class which adds a JSON metadata field to a model,
|
||||
"""Model mixin class which adds a JSON metadata field to a model,
|
||||
for use by any (and all) plugins.
|
||||
|
||||
The intent of this mixin is to provide a metadata field on a model instance,
|
||||
@ -37,8 +34,7 @@ class MetadataMixin(models.Model):
|
||||
)
|
||||
|
||||
def get_metadata(self, key: str, backup_value=None):
|
||||
"""
|
||||
Finds metadata for this model instance, using the provided key for lookup
|
||||
"""Finds metadata for this model instance, using the provided key for lookup
|
||||
|
||||
Args:
|
||||
key: String key for requesting metadata. e.g. if a plugin is accessing the metadata, the plugin slug should be used
|
||||
@ -46,22 +42,19 @@ class MetadataMixin(models.Model):
|
||||
Returns:
|
||||
Python dict object containing requested metadata. If no matching metadata is found, returns None
|
||||
"""
|
||||
|
||||
if self.metadata is None:
|
||||
return backup_value
|
||||
|
||||
return self.metadata.get(key, backup_value)
|
||||
|
||||
def set_metadata(self, key: str, data, commit=True):
|
||||
"""
|
||||
Save the provided metadata under the provided key.
|
||||
"""Save the provided metadata under the provided key.
|
||||
|
||||
Args:
|
||||
key: String key for saving metadata
|
||||
data: Data object to save - must be able to be rendered as a JSON string
|
||||
overwrite: If true, existing metadata with the provided key will be overwritten. If false, a merge will be attempted
|
||||
"""
|
||||
|
||||
if self.metadata is None:
|
||||
# Handle a null field value
|
||||
self.metadata = {}
|
||||
@ -73,14 +66,14 @@ class MetadataMixin(models.Model):
|
||||
|
||||
|
||||
class PluginConfig(models.Model):
|
||||
"""
|
||||
A PluginConfig object holds settings for plugins.
|
||||
"""A PluginConfig object holds settings for plugins.
|
||||
|
||||
Attributes:
|
||||
key: slug of the plugin (this must be unique across all installed plugins!)
|
||||
name: PluginName of the plugin - serves for a manual double check if the right plugin is used
|
||||
active: Should the plugin be loaded?
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Plugin Configuration")
|
||||
verbose_name_plural = _("Plugin Configurations")
|
||||
@ -123,10 +116,7 @@ class PluginConfig(models.Model):
|
||||
# functions
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Override to set original state of the plugin-config instance
|
||||
"""
|
||||
|
||||
"""Override to set original state of the plugin-config instance"""
|
||||
super().__init__(*args, **kwargs)
|
||||
self.__org_active = self.active
|
||||
|
||||
@ -145,9 +135,7 @@ class PluginConfig(models.Model):
|
||||
}
|
||||
|
||||
def save(self, force_insert=False, force_update=False, *args, **kwargs):
|
||||
"""
|
||||
Extend save method to reload plugins if the 'active' status changes
|
||||
"""
|
||||
"""Extend save method to reload plugins if the 'active' status changes"""
|
||||
reload = kwargs.pop('no_reload', False) # check if no_reload flag is set
|
||||
|
||||
ret = super().save(force_insert, force_update, *args, **kwargs)
|
||||
@ -163,9 +151,7 @@ class PluginConfig(models.Model):
|
||||
|
||||
|
||||
class PluginSetting(common.models.BaseInvenTreeSetting):
|
||||
"""
|
||||
This model represents settings for individual plugins
|
||||
"""
|
||||
"""This model represents settings for individual plugins"""
|
||||
|
||||
class Meta:
|
||||
unique_together = [
|
||||
@ -182,8 +168,7 @@ class PluginSetting(common.models.BaseInvenTreeSetting):
|
||||
|
||||
@classmethod
|
||||
def get_setting_definition(cls, key, **kwargs):
|
||||
"""
|
||||
In the BaseInvenTreeSetting class, we have a class attribute named 'SETTINGS',
|
||||
"""In the BaseInvenTreeSetting class, we have a class attribute named 'SETTINGS',
|
||||
which is a dict object that fully defines all the setting parameters.
|
||||
|
||||
Here, unlike the BaseInvenTreeSetting, we do not know the definitions of all settings
|
||||
@ -209,20 +194,14 @@ class PluginSetting(common.models.BaseInvenTreeSetting):
|
||||
return super().get_setting_definition(key, **kwargs)
|
||||
|
||||
def get_kwargs(self):
|
||||
"""
|
||||
Explicit kwargs required to uniquely identify a particular setting object,
|
||||
in addition to the 'key' parameter
|
||||
"""
|
||||
|
||||
"""Explicit kwargs required to uniquely identify a particular setting object, in addition to the 'key' parameter"""
|
||||
return {
|
||||
'plugin': self.plugin,
|
||||
}
|
||||
|
||||
|
||||
class NotificationUserSetting(common.models.BaseInvenTreeSetting):
|
||||
"""
|
||||
This model represents notification settings for a user
|
||||
"""
|
||||
"""This model represents notification settings for a user"""
|
||||
|
||||
class Meta:
|
||||
unique_together = [
|
||||
@ -238,11 +217,7 @@ class NotificationUserSetting(common.models.BaseInvenTreeSetting):
|
||||
return super().get_setting_definition(key, **kwargs)
|
||||
|
||||
def get_kwargs(self):
|
||||
"""
|
||||
Explicit kwargs required to uniquely identify a particular setting object,
|
||||
in addition to the 'key' parameter
|
||||
"""
|
||||
|
||||
"""Explicit kwargs required to uniquely identify a particular setting object, in addition to the 'key' parameter"""
|
||||
return {
|
||||
'method': self.method,
|
||||
'user': self.user,
|
||||
|
@ -1,7 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Base Class for InvenTree plugins
|
||||
"""
|
||||
"""Base Class for InvenTree plugins"""
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
@ -55,24 +53,18 @@ class MetaBase:
|
||||
return value
|
||||
|
||||
def plugin_name(self):
|
||||
"""
|
||||
Name of plugin
|
||||
"""
|
||||
"""Name of plugin"""
|
||||
return self.get_meta_value('NAME', 'PLUGIN_NAME')
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Name of plugin
|
||||
"""
|
||||
"""Name of plugin"""
|
||||
return self.plugin_name()
|
||||
|
||||
def plugin_slug(self):
|
||||
"""
|
||||
Slug of plugin
|
||||
If not set plugin name slugified
|
||||
"""
|
||||
"""Slug of plugin
|
||||
|
||||
If not set plugin name slugified"""
|
||||
slug = self.get_meta_value('SLUG', 'PLUGIN_SLUG', None)
|
||||
if not slug:
|
||||
slug = self.plugin_name()
|
||||
@ -81,16 +73,11 @@ class MetaBase:
|
||||
|
||||
@property
|
||||
def slug(self):
|
||||
"""
|
||||
Slug of plugin
|
||||
"""
|
||||
"""Slug of plugin"""
|
||||
return self.plugin_slug()
|
||||
|
||||
def plugin_title(self):
|
||||
"""
|
||||
Title of plugin
|
||||
"""
|
||||
|
||||
"""Title of plugin"""
|
||||
title = self.get_meta_value('TITLE', 'PLUGIN_TITLE', None)
|
||||
if title:
|
||||
return title
|
||||
@ -98,16 +85,11 @@ class MetaBase:
|
||||
|
||||
@property
|
||||
def human_name(self):
|
||||
"""
|
||||
Human readable name of plugin
|
||||
"""
|
||||
"""Human readable name of plugin"""
|
||||
return self.plugin_title()
|
||||
|
||||
def plugin_config(self):
|
||||
"""
|
||||
Return the PluginConfig object associated with this plugin
|
||||
"""
|
||||
|
||||
"""Return the PluginConfig object associated with this plugin"""
|
||||
try:
|
||||
import plugin.models
|
||||
|
||||
@ -121,10 +103,7 @@ class MetaBase:
|
||||
return cfg
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
Return True if this plugin is currently active
|
||||
"""
|
||||
|
||||
"""Return True if this plugin is currently active"""
|
||||
cfg = self.plugin_config()
|
||||
|
||||
if cfg:
|
||||
@ -134,9 +113,7 @@ class MetaBase:
|
||||
|
||||
|
||||
class MixinBase:
|
||||
"""
|
||||
Base set of mixin functions and mechanisms
|
||||
"""
|
||||
"""Base set of mixin functions and mechanisms"""
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
self._mixinreg = {}
|
||||
@ -144,15 +121,11 @@ class MixinBase:
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def mixin(self, key):
|
||||
"""
|
||||
Check if mixin is registered
|
||||
"""
|
||||
"""Check if mixin is registered"""
|
||||
return key in self._mixins
|
||||
|
||||
def mixin_enabled(self, key):
|
||||
"""
|
||||
Check if mixin is registered, enabled and ready
|
||||
"""
|
||||
"""Check if mixin is registered, enabled and ready"""
|
||||
if self.mixin(key):
|
||||
fnc_name = self._mixins.get(key)
|
||||
|
||||
@ -164,18 +137,12 @@ class MixinBase:
|
||||
return False
|
||||
|
||||
def add_mixin(self, key: str, fnc_enabled=True, cls=None):
|
||||
"""
|
||||
Add a mixin to the plugins registry
|
||||
"""
|
||||
|
||||
"""Add a mixin to the plugins registry"""
|
||||
self._mixins[key] = fnc_enabled
|
||||
self.setup_mixin(key, cls=cls)
|
||||
|
||||
def setup_mixin(self, key, cls=None):
|
||||
"""
|
||||
Define mixin details for the current mixin -> provides meta details for all active mixins
|
||||
"""
|
||||
|
||||
"""Define mixin details for the current mixin -> provides meta details for all active mixins"""
|
||||
# get human name
|
||||
human_name = getattr(cls.MixinMeta, 'MIXIN_NAME', key) if cls and hasattr(cls, 'MixinMeta') else key
|
||||
|
||||
@ -187,10 +154,7 @@ class MixinBase:
|
||||
|
||||
@property
|
||||
def registered_mixins(self, with_base: bool = False):
|
||||
"""
|
||||
Get all registered mixins for the plugin
|
||||
"""
|
||||
|
||||
"""Get all registered mixins for the plugin"""
|
||||
mixins = getattr(self, '_mixinreg', None)
|
||||
if mixins:
|
||||
# filter out base
|
||||
@ -202,8 +166,7 @@ class MixinBase:
|
||||
|
||||
|
||||
class InvenTreePlugin(MixinBase, MetaBase):
|
||||
"""
|
||||
The InvenTreePlugin class is used to integrate with 3rd party software
|
||||
"""The InvenTreePlugin class is used to integrate with 3rd party software
|
||||
|
||||
DO NOT USE THIS DIRECTLY, USE plugin.InvenTreePlugin
|
||||
"""
|
||||
@ -226,9 +189,7 @@ class InvenTreePlugin(MixinBase, MetaBase):
|
||||
# region properties
|
||||
@property
|
||||
def description(self):
|
||||
"""
|
||||
Description of plugin
|
||||
"""
|
||||
"""Description of plugin"""
|
||||
description = getattr(self, 'DESCRIPTION', None)
|
||||
if not description:
|
||||
description = self.plugin_name()
|
||||
@ -236,9 +197,7 @@ class InvenTreePlugin(MixinBase, MetaBase):
|
||||
|
||||
@property
|
||||
def author(self):
|
||||
"""
|
||||
Author of plugin - either from plugin settings or git
|
||||
"""
|
||||
"""Author of plugin - either from plugin settings or git"""
|
||||
author = getattr(self, 'AUTHOR', None)
|
||||
if not author:
|
||||
author = self.package.get('author')
|
||||
@ -248,9 +207,7 @@ class InvenTreePlugin(MixinBase, MetaBase):
|
||||
|
||||
@property
|
||||
def pub_date(self):
|
||||
"""
|
||||
Publishing date of plugin - either from plugin settings or git
|
||||
"""
|
||||
"""Publishing date of plugin - either from plugin settings or git"""
|
||||
pub_date = getattr(self, 'PUBLISH_DATE', None)
|
||||
if not pub_date:
|
||||
pub_date = self.package.get('date')
|
||||
@ -262,77 +219,57 @@ class InvenTreePlugin(MixinBase, MetaBase):
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
"""
|
||||
Version of plugin
|
||||
"""
|
||||
"""Version of plugin"""
|
||||
version = getattr(self, 'VERSION', None)
|
||||
return version
|
||||
|
||||
@property
|
||||
def website(self):
|
||||
"""
|
||||
Website of plugin - if set else None
|
||||
"""
|
||||
"""Website of plugin - if set else None"""
|
||||
website = getattr(self, 'WEBSITE', None)
|
||||
return website
|
||||
|
||||
@property
|
||||
def license(self):
|
||||
"""
|
||||
License of plugin
|
||||
"""
|
||||
"""License of plugin"""
|
||||
lic = getattr(self, 'LICENSE', None)
|
||||
return lic
|
||||
# endregion
|
||||
|
||||
@property
|
||||
def _is_package(self):
|
||||
"""
|
||||
Is the plugin delivered as a package
|
||||
"""
|
||||
"""Is the plugin delivered as a package"""
|
||||
return getattr(self, 'is_package', False)
|
||||
|
||||
@property
|
||||
def is_sample(self):
|
||||
"""
|
||||
Is this plugin part of the samples?
|
||||
"""
|
||||
"""Is this plugin part of the samples?"""
|
||||
path = str(self.package_path)
|
||||
return path.startswith('plugin/samples/')
|
||||
|
||||
@property
|
||||
def package_path(self):
|
||||
"""
|
||||
Path to the plugin
|
||||
"""
|
||||
"""Path to the plugin"""
|
||||
if self._is_package:
|
||||
return self.__module__ # pragma: no cover
|
||||
return pathlib.Path(self.def_path).relative_to(settings.BASE_DIR)
|
||||
|
||||
@property
|
||||
def settings_url(self):
|
||||
"""
|
||||
URL to the settings panel for this plugin
|
||||
"""
|
||||
"""URL to the settings panel for this plugin"""
|
||||
return f'{reverse("settings")}#select-plugin-{self.slug}'
|
||||
|
||||
# region package info
|
||||
def _get_package_commit(self):
|
||||
"""
|
||||
Get last git commit for the plugin
|
||||
"""
|
||||
"""Get last git commit for the plugin"""
|
||||
return get_git_log(self.def_path)
|
||||
|
||||
def _get_package_metadata(self):
|
||||
"""
|
||||
Get package metadata for plugin
|
||||
"""
|
||||
"""Get package metadata for plugin"""
|
||||
return {} # pragma: no cover # TODO add usage for package metadata
|
||||
|
||||
def define_package(self):
|
||||
"""
|
||||
Add package info of the plugin into plugins context
|
||||
"""
|
||||
"""Add package info of the plugin into plugins context"""
|
||||
package = self._get_package_metadata() if self._is_package else self._get_package_commit()
|
||||
|
||||
# process date
|
||||
|
@ -30,9 +30,7 @@ logger = logging.getLogger('inventree')
|
||||
|
||||
|
||||
class PluginsRegistry:
|
||||
"""
|
||||
The PluginsRegistry class
|
||||
"""
|
||||
"""The PluginsRegistry class"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
# plugin registry
|
||||
@ -54,10 +52,7 @@ class PluginsRegistry:
|
||||
self.mixins_settings = {}
|
||||
|
||||
def get_plugin(self, slug):
|
||||
"""
|
||||
Lookup plugin by slug (unique key).
|
||||
"""
|
||||
|
||||
"""Lookup plugin by slug (unique key)."""
|
||||
if slug not in self.plugins:
|
||||
logger.warning(f"Plugin registry has no record of plugin '{slug}'")
|
||||
return None
|
||||
@ -65,15 +60,13 @@ class PluginsRegistry:
|
||||
return self.plugins[slug]
|
||||
|
||||
def call_plugin_function(self, slug, func, *args, **kwargs):
|
||||
"""
|
||||
Call a member function (named by 'func') of the plugin named by 'slug'.
|
||||
"""Call a member function (named by 'func') of the plugin named by 'slug'.
|
||||
|
||||
As this is intended to be run by the background worker,
|
||||
we do not perform any try/except here.
|
||||
|
||||
Instead, any error messages are returned to the worker.
|
||||
"""
|
||||
|
||||
plugin = self.get_plugin(slug)
|
||||
|
||||
if not plugin:
|
||||
@ -86,9 +79,7 @@ class PluginsRegistry:
|
||||
# region public functions
|
||||
# region loading / unloading
|
||||
def load_plugins(self):
|
||||
"""
|
||||
Load and activate all IntegrationPlugins
|
||||
"""
|
||||
"""Load and activate all IntegrationPlugins"""
|
||||
if not settings.PLUGINS_ENABLED:
|
||||
# Plugins not enabled, do nothing
|
||||
return # pragma: no cover
|
||||
@ -143,10 +134,7 @@ class PluginsRegistry:
|
||||
logger.info('Finished loading plugins')
|
||||
|
||||
def unload_plugins(self):
|
||||
"""
|
||||
Unload and deactivate all IntegrationPlugins
|
||||
"""
|
||||
|
||||
"""Unload and deactivate all IntegrationPlugins"""
|
||||
if not settings.PLUGINS_ENABLED:
|
||||
# Plugins not enabled, do nothing
|
||||
return # pragma: no cover
|
||||
@ -170,10 +158,7 @@ class PluginsRegistry:
|
||||
logger.info('Finished unloading plugins')
|
||||
|
||||
def reload_plugins(self):
|
||||
"""
|
||||
Safely reload IntegrationPlugins
|
||||
"""
|
||||
|
||||
"""Safely reload IntegrationPlugins"""
|
||||
# Do not reload whe currently loading
|
||||
if self.is_loading:
|
||||
return # pragma: no cover
|
||||
@ -188,7 +173,6 @@ class PluginsRegistry:
|
||||
|
||||
def collect_plugins(self):
|
||||
"""Collect plugins from all possible ways of loading"""
|
||||
|
||||
if not settings.PLUGINS_ENABLED:
|
||||
# Plugins not enabled, do nothing
|
||||
return # pragma: no cover
|
||||
@ -217,10 +201,7 @@ class PluginsRegistry:
|
||||
logger.info(", ".join([a.__module__ for a in self.plugin_modules]))
|
||||
|
||||
def install_plugin_file(self):
|
||||
"""
|
||||
Make sure all plugins are installed in the current enviroment
|
||||
"""
|
||||
|
||||
"""Make sure all plugins are installed in the current enviroment"""
|
||||
if settings.PLUGIN_FILE_CHECKED:
|
||||
logger.info('Plugin file was already checked')
|
||||
return True
|
||||
@ -241,9 +222,7 @@ class PluginsRegistry:
|
||||
|
||||
# region registry functions
|
||||
def with_mixin(self, mixin: str, active=None):
|
||||
"""
|
||||
Returns reference to all plugins that have a specified mixin enabled
|
||||
"""
|
||||
"""Returns reference to all plugins that have a specified mixin enabled"""
|
||||
result = []
|
||||
|
||||
for plugin in self.plugins.values():
|
||||
@ -264,14 +243,12 @@ class PluginsRegistry:
|
||||
|
||||
# region general internal loading /activating / deactivating / deloading
|
||||
def _init_plugins(self, disabled=None):
|
||||
"""
|
||||
Initialise all found plugins
|
||||
"""Initialise all found plugins
|
||||
|
||||
:param disabled: loading path of disabled app, defaults to None
|
||||
:type disabled: str, optional
|
||||
:raises error: IntegrationPluginError
|
||||
"""
|
||||
|
||||
from plugin.models import PluginConfig
|
||||
|
||||
logger.info('Starting plugin initialisation')
|
||||
@ -335,8 +312,7 @@ class PluginsRegistry:
|
||||
self.plugins_inactive[plug_key] = plugin_db_setting # pragma: no cover
|
||||
|
||||
def _activate_plugins(self, force_reload=False):
|
||||
"""
|
||||
Run activation functions for all plugins
|
||||
"""Run activation functions for all plugins
|
||||
|
||||
:param force_reload: force reload base apps, defaults to False
|
||||
:type force_reload: bool, optional
|
||||
@ -351,7 +327,6 @@ class PluginsRegistry:
|
||||
|
||||
def _deactivate_plugins(self):
|
||||
"""Run deactivation functions for all plugins"""
|
||||
|
||||
self.deactivate_plugin_app()
|
||||
self.deactivate_plugin_schedule()
|
||||
self.deactivate_plugin_settings()
|
||||
@ -425,15 +400,14 @@ class PluginsRegistry:
|
||||
logger.warning("activate_integration_schedule failed, database not ready")
|
||||
|
||||
def deactivate_plugin_schedule(self):
|
||||
"""
|
||||
Deactivate ScheduleMixin
|
||||
"""Deactivate ScheduleMixin
|
||||
|
||||
currently nothing is done
|
||||
"""
|
||||
pass
|
||||
|
||||
def activate_plugin_app(self, plugins, force_reload=False):
|
||||
"""
|
||||
Activate AppMixin plugins - add custom apps and reload
|
||||
"""Activate AppMixin plugins - add custom apps and reload
|
||||
|
||||
:param plugins: list of IntegrationPlugins that should be installed
|
||||
:type plugins: dict
|
||||
@ -471,9 +445,10 @@ class PluginsRegistry:
|
||||
self._update_urls()
|
||||
|
||||
def _reregister_contrib_apps(self):
|
||||
"""fix reloading of contrib apps - models and admin
|
||||
this is needed if plugins were loaded earlier and then reloaded as models and admins rely on imports
|
||||
those register models and admin in their respective objects (e.g. admin.site for admin)
|
||||
"""Fix reloading of contrib apps - models and admin
|
||||
|
||||
This is needed if plugins were loaded earlier and then reloaded as models and admins rely on imports.
|
||||
Those register models and admin in their respective objects (e.g. admin.site for admin).
|
||||
"""
|
||||
for plugin_path in self.installed_apps:
|
||||
try:
|
||||
@ -503,8 +478,9 @@ class PluginsRegistry:
|
||||
reload(app_config.module.admin)
|
||||
|
||||
def _get_plugin_path(self, plugin):
|
||||
"""parse plugin path
|
||||
the input can be eiter:
|
||||
"""Parse plugin path
|
||||
|
||||
The input can be eiter:
|
||||
- a local file / dir
|
||||
- a package
|
||||
"""
|
||||
@ -518,7 +494,6 @@ class PluginsRegistry:
|
||||
|
||||
def deactivate_plugin_app(self):
|
||||
"""Deactivate AppMixin plugins - some magic required"""
|
||||
|
||||
# unregister models from admin
|
||||
for plugin_path in self.installed_apps:
|
||||
models = [] # the modelrefs need to be collected as poping an item in a iter is not welcomed
|
||||
@ -601,9 +576,9 @@ class PluginsRegistry:
|
||||
self.is_loading = False
|
||||
|
||||
def _try_reload(self, cmd, *args, **kwargs):
|
||||
"""
|
||||
wrapper to try reloading the apps
|
||||
throws an custom error that gets handled by the loading function
|
||||
"""Wrapper to try reloading the apps
|
||||
|
||||
Throws an custom error that gets handled by the loading function
|
||||
"""
|
||||
try:
|
||||
cmd(*args, **kwargs)
|
||||
@ -617,5 +592,5 @@ registry = PluginsRegistry()
|
||||
|
||||
|
||||
def call_function(plugin_name, function_name, *args, **kwargs):
|
||||
""" Global helper function to call a specific member function of a plugin """
|
||||
"""Global helper function to call a specific member function of a plugin"""
|
||||
return registry.call_plugin_function(plugin_name, function_name, *args, **kwargs)
|
||||
|
Loading…
Reference in New Issue
Block a user